mirror of
https://github.com/jemalloc/jemalloc.git
synced 2026-07-22 12:43:16 +00:00
Compare commits
175 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
446c3b22f1 | ||
|
|
4c48481e7c | ||
|
|
746e77a06b | ||
|
|
f9a8edbb50 | ||
|
|
f0b22cf932 | ||
|
|
408ade6545 | ||
|
|
955851f384 | ||
|
|
7427525c28 | ||
|
|
64ba3d7cd9 | ||
|
|
5ef7abf6d8 | ||
|
|
7d9ebea57d | ||
|
|
3e292475ee | ||
|
|
9f949f9d82 | ||
|
|
69c0472999 | ||
|
|
af8ad3ec6a | ||
|
|
adc675c8ef | ||
|
|
38d9210c46 | ||
|
|
eacb896c01 | ||
|
|
c957398b4f | ||
|
|
fb4e26aa9e | ||
|
|
4bcd987251 | ||
|
|
47e57f9bda | ||
|
|
1dcb4f86b2 | ||
|
|
893a0ed7c8 | ||
|
|
763baa6cfc | ||
|
|
9a8fc41bb9 | ||
|
|
92d3284ff8 | ||
|
|
0657f12acd | ||
|
|
597632be18 | ||
|
|
9c43c13a35 | ||
|
|
84c8eefeff | ||
|
|
77f350be08 | ||
|
|
b602daa671 | ||
|
|
819d11be06 | ||
|
|
49f7e8f35a | ||
|
|
1b17768e24 | ||
|
|
41ade967c2 | ||
|
|
ff7450727f | ||
|
|
fa5d245aef | ||
|
|
ad11ee6a34 | ||
|
|
0e4d0d13f9 | ||
|
|
a8118233ec | ||
|
|
a7153a0d7d | ||
|
|
814b9bda7f | ||
|
|
e27d134efc | ||
|
|
6e56e5ec6a | ||
|
|
af5d6987f8 | ||
|
|
655f04a5a4 | ||
|
|
9dcad2dfd1 | ||
|
|
6369286f83 | ||
|
|
a73ebd946a | ||
|
|
ada55b2e92 | ||
|
|
31bfb3e7b0 | ||
|
|
f256680f87 | ||
|
|
dbd3832d20 | ||
|
|
10e4523094 | ||
|
|
624f2f3cc9 | ||
|
|
8ad0eacfb3 | ||
|
|
2a6f2af6e4 | ||
|
|
2b769797ce | ||
|
|
50ac670d09 | ||
|
|
1c4b088b08 | ||
|
|
0e8d3d2cb9 | ||
|
|
ecf229a39f | ||
|
|
cfdc8cfbd6 | ||
|
|
aee7fd2b70 | ||
|
|
fc4dcfa2f5 | ||
|
|
1f17bd9395 | ||
|
|
0a36622dd1 | ||
|
|
53806fef53 | ||
|
|
b04a940ee5 | ||
|
|
d4bab21756 | ||
|
|
b059a534f7 | ||
|
|
a39d5b6ef2 | ||
|
|
3af83344a5 | ||
|
|
0176e3057d | ||
|
|
379f847f44 | ||
|
|
ce93055c49 | ||
|
|
0d38791e7a | ||
|
|
8da141f47a | ||
|
|
49d0293c88 | ||
|
|
e73397062a | ||
|
|
e4f7846f1f | ||
|
|
81b4e6eb6f | ||
|
|
4d6a134e13 | ||
|
|
93443689a4 | ||
|
|
21fb95bba6 | ||
|
|
088e6a0a37 | ||
|
|
8de6a02823 | ||
|
|
12ca91402b | ||
|
|
940a2e02b2 | ||
|
|
397e5111b5 | ||
|
|
004ed142a6 | ||
|
|
ac6f3c2bb5 | ||
|
|
9f3b0a74fd | ||
|
|
1506a1b903 | ||
|
|
c6e950665c | ||
|
|
9ce3bfd92d | ||
|
|
588a32cd84 | ||
|
|
a881cd2c61 | ||
|
|
4d5c09905e | ||
|
|
3c26a7d68e | ||
|
|
d65cdfe233 | ||
|
|
c2fc8c8b3a | ||
|
|
3377ffa1f4 | ||
|
|
7393f44ff0 | ||
|
|
37dab02e52 | ||
|
|
6005f0710c | ||
|
|
075e77cad4 | ||
|
|
355b438c85 | ||
|
|
6a0d2918ce | ||
|
|
a09f55c87d | ||
|
|
28177d466f | ||
|
|
79d660d35d | ||
|
|
a094babe33 | ||
|
|
8e3c3c61b5 | ||
|
|
4cc6a60a4f | ||
|
|
8d7a94b275 | ||
|
|
7e11b389aa | ||
|
|
58a6f5c9be | ||
|
|
2dbecf1f62 | ||
|
|
b267d0f86a | ||
|
|
e139ab8b4f | ||
|
|
dcd15098a8 | ||
|
|
2541e1b083 | ||
|
|
b43b7750a6 | ||
|
|
e13243eb63 | ||
|
|
7013d10a9e | ||
|
|
ed3d152ea0 | ||
|
|
2206e1acc1 | ||
|
|
ecea0f6125 | ||
|
|
1af6ac42e3 | ||
|
|
5055f4516c | ||
|
|
38cda690dd | ||
|
|
6d68ed6492 | ||
|
|
8d4203c72d | ||
|
|
5065156f3f | ||
|
|
1bb602125c | ||
|
|
5523399169 | ||
|
|
5fe764f83f | ||
|
|
799ca0b68d | ||
|
|
68f91893bd | ||
|
|
3395860921 | ||
|
|
0656ec0eb4 | ||
|
|
af366593a4 | ||
|
|
7cb5b5ea21 | ||
|
|
fd88bd577e | ||
|
|
ec5344eba2 | ||
|
|
a53610130d | ||
|
|
a91f210929 | ||
|
|
18ad8234b6 | ||
|
|
f18c982001 | ||
|
|
a02fc08ec9 | ||
|
|
0b270a991d | ||
|
|
169cbc1ef7 | ||
|
|
c03a63d68d | ||
|
|
19b3d61892 | ||
|
|
dafde14e08 | ||
|
|
e69bee01de | ||
|
|
f00bb7f132 | ||
|
|
6b5974403b | ||
|
|
d9ef75fed4 | ||
|
|
992242c545 | ||
|
|
19b6a5537d | ||
|
|
e00572b384 | ||
|
|
05b21be347 | ||
|
|
86815df9dc | ||
|
|
1e0a636c11 | ||
|
|
3fa9a2fad8 | ||
|
|
2caa4715ed | ||
|
|
3c2d9c899c | ||
|
|
698805c525 | ||
|
|
cfeccd34a3 | ||
|
|
9df0215f9b | ||
|
|
ca6bd4f1c8 |
40
.gitignore
vendored
40
.gitignore
vendored
@@ -1,17 +1,23 @@
|
|||||||
/jemalloc/autom4te.cache/
|
/autom4te.cache/
|
||||||
/jemalloc/bin/
|
/config.stamp
|
||||||
/jemalloc/cfghdrs.stamp
|
/config.log
|
||||||
/jemalloc/cfgoutputs.stamp
|
/config.status
|
||||||
/jemalloc/config.log
|
/configure
|
||||||
/jemalloc/config.status
|
/doc/html.xsl
|
||||||
/jemalloc/configure
|
/doc/manpages.xsl
|
||||||
/jemalloc/doc/jemalloc.3
|
/doc/jemalloc.xml
|
||||||
/jemalloc/lib/
|
/doc/jemalloc.html
|
||||||
/jemalloc/Makefile
|
/doc/jemalloc.3
|
||||||
/jemalloc/src/internal/jemalloc_internal\.h
|
/lib/
|
||||||
/jemalloc/src/internal/mtrgraph_defs\.h
|
/Makefile
|
||||||
/jemalloc/src/internal/mtrplay_defs\.h
|
/include/jemalloc/internal/jemalloc_internal\.h
|
||||||
/jemalloc/src/jemalloc\.h
|
/include/jemalloc/jemalloc\.h
|
||||||
/jemalloc/src/jemalloc_defs\.h
|
/include/jemalloc/jemalloc_defs\.h
|
||||||
/jemalloc/src/*.[od]
|
/test/jemalloc_test\.h
|
||||||
/jemalloc/VERSION
|
/src/*.[od]
|
||||||
|
/test/*.[od]
|
||||||
|
/test/*.out
|
||||||
|
/test/[a-z]*
|
||||||
|
!test/*.c
|
||||||
|
!test/*.exp
|
||||||
|
/VERSION
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ subject to the following licenses:
|
|||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
Copyright (C) 2002-2010 Jason Evans <jasone@canonware.com>.
|
Copyright (C) 2002-2010 Jason Evans <jasone@canonware.com>.
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
Copyright (C) 2007-2010 Mozilla Foundation. All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
@@ -23,7 +24,7 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|||||||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
Copyright (C) 2009 Facebook, Inc.
|
Copyright (C) 2009-2010 Facebook, Inc.
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification,
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
221
ChangeLog
Normal file
221
ChangeLog
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
Following are change highlights associated with official releases. Important
|
||||||
|
bug fixes are all mentioned, but internal enhancements are omitted here for
|
||||||
|
brevity (even though they are more fun to write about). Much more detail can be
|
||||||
|
found in the git revision history:
|
||||||
|
|
||||||
|
http://www.canonware.com/cgi-bin/gitweb.cgi?p=jemalloc.git
|
||||||
|
git://canonware.com/jemalloc.git
|
||||||
|
|
||||||
|
* 2.2.2 (July 30, 2011)
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
- Fix a build error for --disable-tcache.
|
||||||
|
- Fix assertions in arena_purge() (for real this time).
|
||||||
|
- Add the --with-private-namespace option. This is a workaround for symbol
|
||||||
|
conflicts that can inadvertently arise when using static libraries.
|
||||||
|
|
||||||
|
* 2.2.1 (March 30, 2011)
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
- Implement atomic operations for x86/x64. This fixes compilation failures
|
||||||
|
for versions of gcc that are still in wide use.
|
||||||
|
- Fix an assertion in arena_purge().
|
||||||
|
|
||||||
|
* 2.2.0 (March 22, 2011)
|
||||||
|
|
||||||
|
This version incorporates several improvements to algorithms and data
|
||||||
|
structures that tend to reduce fragmentation and increase speed.
|
||||||
|
|
||||||
|
New features:
|
||||||
|
- Add the "stats.cactive" mallctl.
|
||||||
|
- Update pprof (from google-perftools 1.7).
|
||||||
|
- Improve backtracing-related configuration logic, and add the
|
||||||
|
--disable-prof-libgcc option.
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
- Change default symbol visibility from "internal", to "hidden", which
|
||||||
|
decreases the overhead of library-internal function calls.
|
||||||
|
- Fix symbol visibility so that it is also set on OS X.
|
||||||
|
- Fix a build dependency regression caused by the introduction of the .pic.o
|
||||||
|
suffix for PIC object files.
|
||||||
|
- Add missing checks for mutex initialization failures.
|
||||||
|
- Don't use libgcc-based backtracing except on x64, where it is known to work.
|
||||||
|
- Fix deadlocks on OS X that were due to memory allocation in
|
||||||
|
pthread_mutex_lock().
|
||||||
|
- Heap profiling-specific fixes:
|
||||||
|
+ Fix memory corruption due to integer overflow in small region index
|
||||||
|
computation, when using a small enough sample interval that profiling
|
||||||
|
context pointers are stored in small run headers.
|
||||||
|
+ Fix a bootstrap ordering bug that only occurred with TLS disabled.
|
||||||
|
+ Fix a rallocm() rsize bug.
|
||||||
|
+ Fix error detection bugs for aligned memory allocation.
|
||||||
|
|
||||||
|
* 2.1.3 (March 14, 2011)
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
- Fix a cpp logic regression (due to the "thread.{de,}allocatedp" mallctl fix
|
||||||
|
for OS X in 2.1.2).
|
||||||
|
- Fix a "thread.arena" mallctl bug.
|
||||||
|
- Fix a thread cache stats merging bug.
|
||||||
|
|
||||||
|
* 2.1.2 (March 2, 2011)
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
- Fix "thread.{de,}allocatedp" mallctl for OS X.
|
||||||
|
- Add missing jemalloc.a to build system.
|
||||||
|
|
||||||
|
* 2.1.1 (January 31, 2011)
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
- Fix aligned huge reallocation (affected allocm()).
|
||||||
|
- Fix the ALLOCM_LG_ALIGN macro definition.
|
||||||
|
- Fix a heap dumping deadlock.
|
||||||
|
- Fix a "thread.arena" mallctl bug.
|
||||||
|
|
||||||
|
* 2.1.0 (December 3, 2010)
|
||||||
|
|
||||||
|
This version incorporates some optimizations that can't quite be considered
|
||||||
|
bug fixes.
|
||||||
|
|
||||||
|
New features:
|
||||||
|
- Use Linux's mremap(2) for huge object reallocation when possible.
|
||||||
|
- Avoid locking in mallctl*() when possible.
|
||||||
|
- Add the "thread.[de]allocatedp" mallctl's.
|
||||||
|
- Convert the manual page source from roff to DocBook, and generate both roff
|
||||||
|
and HTML manuals.
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
- Fix a crash due to incorrect bootstrap ordering. This only impacted
|
||||||
|
--enable-debug --enable-dss configurations.
|
||||||
|
- Fix a minor statistics bug for mallctl("swap.avail", ...).
|
||||||
|
|
||||||
|
* 2.0.1 (October 29, 2010)
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
- Fix a race condition in heap profiling that could cause undefined behavior
|
||||||
|
if "opt.prof_accum" were disabled.
|
||||||
|
- Add missing mutex unlocks for some OOM error paths in the heap profiling
|
||||||
|
code.
|
||||||
|
- Fix a compilation error for non-C99 builds.
|
||||||
|
|
||||||
|
* 2.0.0 (October 24, 2010)
|
||||||
|
|
||||||
|
This version focuses on the experimental *allocm() API, and on improved
|
||||||
|
run-time configuration/introspection. Nonetheless, numerous performance
|
||||||
|
improvements are also included.
|
||||||
|
|
||||||
|
New features:
|
||||||
|
- Implement the experimental {,r,s,d}allocm() API, which provides a superset
|
||||||
|
of the functionality available via malloc(), calloc(), posix_memalign(),
|
||||||
|
realloc(), malloc_usable_size(), and free(). These functions can be used to
|
||||||
|
allocate/reallocate aligned zeroed memory, ask for optional extra memory
|
||||||
|
during reallocation, prevent object movement during reallocation, etc.
|
||||||
|
- Replace JEMALLOC_OPTIONS/JEMALLOC_PROF_PREFIX with MALLOC_CONF, which is
|
||||||
|
more human-readable, and more flexible. For example:
|
||||||
|
JEMALLOC_OPTIONS=AJP
|
||||||
|
is now:
|
||||||
|
MALLOC_CONF=abort:true,fill:true,stats_print:true
|
||||||
|
- Port to Apple OS X. Sponsored by Mozilla.
|
||||||
|
- Make it possible for the application to control thread-->arena mappings via
|
||||||
|
the "thread.arena" mallctl.
|
||||||
|
- Add compile-time support for all TLS-related functionality via pthreads TSD.
|
||||||
|
This is mainly of interest for OS X, which does not support TLS, but has a
|
||||||
|
TSD implementation with similar performance.
|
||||||
|
- Override memalign() and valloc() if they are provided by the system.
|
||||||
|
- Add the "arenas.purge" mallctl, which can be used to synchronously purge all
|
||||||
|
dirty unused pages.
|
||||||
|
- Make cumulative heap profiling data optional, so that it is possible to
|
||||||
|
limit the amount of memory consumed by heap profiling data structures.
|
||||||
|
- Add per thread allocation counters that can be accessed via the
|
||||||
|
"thread.allocated" and "thread.deallocated" mallctls.
|
||||||
|
|
||||||
|
Incompatible changes:
|
||||||
|
- Remove JEMALLOC_OPTIONS and malloc_options (see MALLOC_CONF above).
|
||||||
|
- Increase default backtrace depth from 4 to 128 for heap profiling.
|
||||||
|
- Disable interval-based profile dumps by default.
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
- Remove bad assertions in fork handler functions. These assertions could
|
||||||
|
cause aborts for some combinations of configure settings.
|
||||||
|
- Fix strerror_r() usage to deal with non-standard semantics in GNU libc.
|
||||||
|
- Fix leak context reporting. This bug tended to cause the number of contexts
|
||||||
|
to be underreported (though the reported number of objects and bytes were
|
||||||
|
correct).
|
||||||
|
- Fix a realloc() bug for large in-place growing reallocation. This bug could
|
||||||
|
cause memory corruption, but it was hard to trigger.
|
||||||
|
- Fix an allocation bug for small allocations that could be triggered if
|
||||||
|
multiple threads raced to create a new run of backing pages.
|
||||||
|
- Enhance the heap profiler to trigger samples based on usable size, rather
|
||||||
|
than request size.
|
||||||
|
- Fix a heap profiling bug due to sometimes losing track of requested object
|
||||||
|
size for sampled objects.
|
||||||
|
|
||||||
|
* 1.0.3 (August 12, 2010)
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
- Fix the libunwind-based implementation of stack backtracing (used for heap
|
||||||
|
profiling). This bug could cause zero-length backtraces to be reported.
|
||||||
|
- Add a missing mutex unlock in library initialization code. If multiple
|
||||||
|
threads raced to initialize malloc, some of them could end up permanently
|
||||||
|
blocked.
|
||||||
|
|
||||||
|
* 1.0.2 (May 11, 2010)
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
- Fix junk filling of large objects, which could cause memory corruption.
|
||||||
|
- Add MAP_NORESERVE support for chunk mapping, because otherwise virtual
|
||||||
|
memory limits could cause swap file configuration to fail. Contributed by
|
||||||
|
Jordan DeLong.
|
||||||
|
|
||||||
|
* 1.0.1 (April 14, 2010)
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
- Fix compilation when --enable-fill is specified.
|
||||||
|
- Fix threads-related profiling bugs that affected accuracy and caused memory
|
||||||
|
to be leaked during thread exit.
|
||||||
|
- Fix dirty page purging race conditions that could cause crashes.
|
||||||
|
- Fix crash in tcache flushing code during thread destruction.
|
||||||
|
|
||||||
|
* 1.0.0 (April 11, 2010)
|
||||||
|
|
||||||
|
This release focuses on speed and run-time introspection. Numerous
|
||||||
|
algorithmic improvements make this release substantially faster than its
|
||||||
|
predecessors.
|
||||||
|
|
||||||
|
New features:
|
||||||
|
- Implement autoconf-based configuration system.
|
||||||
|
- Add mallctl*(), for the purposes of introspection and run-time
|
||||||
|
configuration.
|
||||||
|
- Make it possible for the application to manually flush a thread's cache, via
|
||||||
|
the "tcache.flush" mallctl.
|
||||||
|
- Base maximum dirty page count on proportion of active memory.
|
||||||
|
- Compute various addtional run-time statistics, including per size class
|
||||||
|
statistics for large objects.
|
||||||
|
- Expose malloc_stats_print(), which can be called repeatedly by the
|
||||||
|
application.
|
||||||
|
- Simplify the malloc_message() signature to only take one string argument,
|
||||||
|
and incorporate an opaque data pointer argument for use by the application
|
||||||
|
in combination with malloc_stats_print().
|
||||||
|
- Add support for allocation backed by one or more swap files, and allow the
|
||||||
|
application to disable over-commit if swap files are in use.
|
||||||
|
- Implement allocation profiling and leak checking.
|
||||||
|
|
||||||
|
Removed features:
|
||||||
|
- Remove the dynamic arena rebalancing code, since thread-specific caching
|
||||||
|
reduces its utility.
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
- Modify chunk allocation to work when address space layout randomization
|
||||||
|
(ASLR) is in use.
|
||||||
|
- Fix thread cleanup bugs related to TLS destruction.
|
||||||
|
- Handle 0-size allocation requests in posix_memalign().
|
||||||
|
- Fix a chunk leak. The leaked chunks were never touched, so this impacted
|
||||||
|
virtual memory usage, but not physical memory usage.
|
||||||
|
|
||||||
|
* linux_2008082[78]a (August 27/28, 2008)
|
||||||
|
|
||||||
|
These snapshot releases are the simple result of incorporating Linux-specific
|
||||||
|
support into the FreeBSD malloc sources.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
vim:filetype=text:textwidth=80
|
||||||
@@ -27,37 +27,68 @@ any of the following arguments (not a definitive list) to 'configure':
|
|||||||
it is linked to. This works only on ELF-based systems.
|
it is linked to. This works only on ELF-based systems.
|
||||||
|
|
||||||
--with-jemalloc-prefix=<prefix>
|
--with-jemalloc-prefix=<prefix>
|
||||||
Prefix all public APIs with <prefix>, so that, for example, malloc()
|
Prefix all public APIs with <prefix>. For example, if <prefix> is
|
||||||
becomes <prefix>malloc(). This makes it possible to use jemalloc at the
|
"prefix_", API changes like the following occur:
|
||||||
same time as the system allocator.
|
|
||||||
|
malloc() --> prefix_malloc()
|
||||||
|
malloc_conf --> prefix_malloc_conf
|
||||||
|
/etc/malloc.conf --> /etc/prefix_malloc.conf
|
||||||
|
MALLOC_CONF --> PREFIX_MALLOC_CONF
|
||||||
|
|
||||||
|
This makes it possible to use jemalloc at the same time as the system
|
||||||
|
allocator, or even to use multiple copies of jemalloc simultaneously.
|
||||||
|
|
||||||
|
By default, the prefix is "", except on OS X, where it is "je_". On OS X,
|
||||||
|
jemalloc overlays the default malloc zone, but makes no attempt to actually
|
||||||
|
replace the "malloc", "calloc", etc. symbols.
|
||||||
|
|
||||||
|
--with-private-namespace=<prefix>
|
||||||
|
Prefix all library-private APIs with <prefix>. For shared libraries,
|
||||||
|
symbol visibility mechanisms prevent these symbols from being exported, but
|
||||||
|
for static libraries, naming collisions are a real possibility. By
|
||||||
|
default, the prefix is "" (empty string).
|
||||||
|
|
||||||
--with-install-suffix=<suffix>
|
--with-install-suffix=<suffix>
|
||||||
Append <suffix> to the base name of all installed files, such that multiple
|
Append <suffix> to the base name of all installed files, such that multiple
|
||||||
versions of jemalloc can coexist in the same installation directory. For
|
versions of jemalloc can coexist in the same installation directory. For
|
||||||
example, libjemalloc.so.0 becomes libjemalloc<suffix>.so.0.
|
example, libjemalloc.so.0 becomes libjemalloc<suffix>.so.0.
|
||||||
|
|
||||||
|
--enable-cc-silence
|
||||||
|
Enable code that silences non-useful compiler warnings. This is helpful
|
||||||
|
when trying to tell serious warnings from those due to compiler
|
||||||
|
limitations, but it potentially incurs a performance penalty.
|
||||||
|
|
||||||
--enable-debug
|
--enable-debug
|
||||||
Enable assertions and validation code. This incurs a substantial
|
Enable assertions and validation code. This incurs a substantial
|
||||||
performance hit, but is very useful during application development.
|
performance hit, but is very useful during application development.
|
||||||
|
|
||||||
--enable-stats
|
--enable-stats
|
||||||
Enable statistics gathering functionality. Use the 'P' option to print
|
Enable statistics gathering functionality. See the "opt.stats_print"
|
||||||
detailed allocation statistics at exit.
|
option documentation for usage details.
|
||||||
|
|
||||||
--enable-prof
|
--enable-prof
|
||||||
Enable heap profiling and leak detection functionality. Use the 'B', 'F',
|
Enable heap profiling and leak detection functionality. See the "opt.prof"
|
||||||
'I', 'L', and 'U' options to control these features.
|
option documentation for usage details. When enabled, there are several
|
||||||
|
approaches to backtracing, and the configure script chooses the first one
|
||||||
|
in the following list that appears to function correctly:
|
||||||
|
|
||||||
--disable-prof-libgcc
|
+ libunwind (requires --enable-prof-libunwind)
|
||||||
Disable the use of libgcc's backtracing functionality. Ordinarily, libgcc's
|
+ libgcc (unless --disable-prof-libgcc)
|
||||||
backtracing functionality is superior to the alternatives, but it may fail
|
+ gcc intrinsics (unless --disable-prof-gcc)
|
||||||
to capture backtraces on some systems.
|
|
||||||
|
|
||||||
--enable-prof-libunwind
|
--enable-prof-libunwind
|
||||||
Use the libunwind library (http://www.nongnu.org/libunwind/) for stack
|
Use the libunwind library (http://www.nongnu.org/libunwind/) for stack
|
||||||
backtracing. libunwind is quite slow, but it tends to work across a wider
|
backtracing.
|
||||||
variety of system configurations than the default backtracing code, which is
|
|
||||||
based on libgcc functionality or gcc intrinsics.
|
--disable-prof-libgcc
|
||||||
|
Disable the use of libgcc's backtracing functionality.
|
||||||
|
|
||||||
|
--disable-prof-gcc
|
||||||
|
Disable the use of gcc intrinsics for backtracing.
|
||||||
|
|
||||||
|
--with-static-libunwind=<libunwind.a>
|
||||||
|
Statically link against the specified libunwind.a rather than dynamically
|
||||||
|
linking with -lunwind.
|
||||||
|
|
||||||
--disable-tiny
|
--disable-tiny
|
||||||
Disable tiny (sub-quantum-sized) object support. Technically it is not
|
Disable tiny (sub-quantum-sized) object support. Technically it is not
|
||||||
@@ -67,9 +98,9 @@ any of the following arguments (not a definitive list) to 'configure':
|
|||||||
are 4-byte-aligned.
|
are 4-byte-aligned.
|
||||||
|
|
||||||
--disable-tcache
|
--disable-tcache
|
||||||
Disable thread-specific caches for small and medium objects. Objects are
|
Disable thread-specific caches for small objects. Objects are cached and
|
||||||
cached and released in bulk, thus reducing the total number of mutex
|
released in bulk, thus reducing the total number of mutex operations. See
|
||||||
operations. Use the 'H' and 'G' options to control thread-specific caching.
|
the "opt.tcache" option for usage details.
|
||||||
|
|
||||||
--enable-swap
|
--enable-swap
|
||||||
Enable mmap()ed swap file support. When this feature is built in, it is
|
Enable mmap()ed swap file support. When this feature is built in, it is
|
||||||
@@ -81,18 +112,18 @@ any of the following arguments (not a definitive list) to 'configure':
|
|||||||
mmap(2).
|
mmap(2).
|
||||||
|
|
||||||
--enable-fill
|
--enable-fill
|
||||||
Enable support for junk/zero filling of memory. Use the 'J' option to
|
Enable support for junk/zero filling of memory. See the "opt.junk"/
|
||||||
control junk filling, or the 'Z' option to control zero filling.
|
"opt.zero" option documentation for usage details.
|
||||||
|
|
||||||
--enable-xmalloc
|
--enable-xmalloc
|
||||||
Enable support for optional immediate termination due to out-of-memory
|
Enable support for optional immediate termination due to out-of-memory
|
||||||
errors, as is commonly implemented by "xmalloc" wrapper function for malloc.
|
errors, as is commonly implemented by "xmalloc" wrapper function for malloc.
|
||||||
Use the 'X' option to control termination behavior.
|
See the "opt.xmalloc" option documentation for usage details.
|
||||||
|
|
||||||
--enable-sysv
|
--enable-sysv
|
||||||
Enable support for System V semantics, wherein malloc(0) returns NULL
|
Enable support for System V semantics, wherein malloc(0) returns NULL
|
||||||
rather than a minimal allocation. Use the 'V' option to control System V
|
rather than a minimal allocation. See the "opt.sysv" option documentation
|
||||||
compatibility.
|
for usage details.
|
||||||
|
|
||||||
--enable-dynamic-page-shift
|
--enable-dynamic-page-shift
|
||||||
Under most conditions, the system page size never changes (usually 4KiB or
|
Under most conditions, the system page size never changes (usually 4KiB or
|
||||||
@@ -112,8 +143,11 @@ any of the following arguments (not a definitive list) to 'configure':
|
|||||||
--disable-tls
|
--disable-tls
|
||||||
Disable thread-local storage (TLS), which allows for fast access to
|
Disable thread-local storage (TLS), which allows for fast access to
|
||||||
thread-local variables via the __thread keyword. If TLS is available,
|
thread-local variables via the __thread keyword. If TLS is available,
|
||||||
jemalloc uses it for several purposes. Not that disabling TLS implies
|
jemalloc uses it for several purposes.
|
||||||
--disable-tcache.
|
|
||||||
|
--with-xslroot=<path>
|
||||||
|
Specify where to find DocBook XSL stylesheets when building the
|
||||||
|
documentation.
|
||||||
|
|
||||||
The following environment variables (not a definitive list) impact configure's
|
The following environment variables (not a definitive list) impact configure's
|
||||||
behavior:
|
behavior:
|
||||||
@@ -147,9 +181,12 @@ PATH="?"
|
|||||||
|
|
||||||
=== Advanced compilation =======================================================
|
=== Advanced compilation =======================================================
|
||||||
|
|
||||||
To run integrated regression tests, type:
|
To install only parts of jemalloc, use the following targets:
|
||||||
|
|
||||||
make check
|
install_bin
|
||||||
|
install_include
|
||||||
|
install_lib
|
||||||
|
install_doc
|
||||||
|
|
||||||
To clean up build results to varying degrees, use the following make targets:
|
To clean up build results to varying degrees, use the following make targets:
|
||||||
|
|
||||||
@@ -171,6 +208,10 @@ LIBDIR="?"
|
|||||||
MANDIR="?"
|
MANDIR="?"
|
||||||
Use this as the installation prefix for man pages.
|
Use this as the installation prefix for man pages.
|
||||||
|
|
||||||
|
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.
|
Use this to invoke the C compiler.
|
||||||
|
|
||||||
@@ -202,3 +243,15 @@ directory, issue configuration and build commands:
|
|||||||
cd obj
|
cd obj
|
||||||
../configure --enable-autogen
|
../configure --enable-autogen
|
||||||
make
|
make
|
||||||
|
|
||||||
|
=== 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
|
||||||
|
prior to installation via any of the following commands:
|
||||||
|
|
||||||
|
nroff -man -t doc/jemalloc.3
|
||||||
|
|
||||||
|
groff -man -t -Tps doc/jemalloc.3 | ps2pdf - doc/jemalloc.3.pdf
|
||||||
|
|
||||||
|
(cd doc; groff -man -man-ext -t -Thtml jemalloc.3 > jemalloc.3.html)
|
||||||
259
Makefile.in
Normal file
259
Makefile.in
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
# Clear out all vpaths, then set just one (default vpath) for the main build
|
||||||
|
# directory.
|
||||||
|
vpath
|
||||||
|
vpath % .
|
||||||
|
|
||||||
|
# Clear the default suffixes, so that built-in rules are not used.
|
||||||
|
.SUFFIXES :
|
||||||
|
|
||||||
|
SHELL := /bin/sh
|
||||||
|
|
||||||
|
CC := @CC@
|
||||||
|
|
||||||
|
# Configuration parameters.
|
||||||
|
DESTDIR =
|
||||||
|
BINDIR := $(DESTDIR)@BINDIR@
|
||||||
|
INCLUDEDIR := $(DESTDIR)@INCLUDEDIR@
|
||||||
|
LIBDIR := $(DESTDIR)@LIBDIR@
|
||||||
|
DATADIR := $(DESTDIR)@DATADIR@
|
||||||
|
MANDIR := $(DESTDIR)@MANDIR@
|
||||||
|
|
||||||
|
# Build parameters.
|
||||||
|
CPPFLAGS := @CPPFLAGS@ -I@srcroot@include -I@objroot@include
|
||||||
|
CFLAGS := @CFLAGS@
|
||||||
|
ifeq (macho, @abi@)
|
||||||
|
CFLAGS += -dynamic
|
||||||
|
endif
|
||||||
|
LDFLAGS := @LDFLAGS@
|
||||||
|
LIBS := @LIBS@
|
||||||
|
RPATH_EXTRA := @RPATH_EXTRA@
|
||||||
|
ifeq (macho, @abi@)
|
||||||
|
SO := dylib
|
||||||
|
WL_SONAME := dylib_install_name
|
||||||
|
else
|
||||||
|
SO := so
|
||||||
|
WL_SONAME := soname
|
||||||
|
endif
|
||||||
|
REV := 1
|
||||||
|
ifeq (macho, @abi@)
|
||||||
|
TEST_LIBRARY_PATH := DYLD_FALLBACK_LIBRARY_PATH=@objroot@lib
|
||||||
|
else
|
||||||
|
TEST_LIBRARY_PATH :=
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Lists of files.
|
||||||
|
BINS := @srcroot@bin/pprof
|
||||||
|
CHDRS := @objroot@include/jemalloc/jemalloc@install_suffix@.h \
|
||||||
|
@objroot@include/jemalloc/jemalloc_defs@install_suffix@.h
|
||||||
|
CSRCS := @srcroot@src/jemalloc.c @srcroot@src/arena.c @srcroot@src/atomic.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/chunk_swap.c @srcroot@src/ckh.c @srcroot@src/ctl.c \
|
||||||
|
@srcroot@src/extent.c @srcroot@src/hash.c @srcroot@src/huge.c \
|
||||||
|
@srcroot@src/mb.c @srcroot@src/mutex.c @srcroot@src/prof.c \
|
||||||
|
@srcroot@src/rtree.c @srcroot@src/stats.c @srcroot@src/tcache.c
|
||||||
|
ifeq (macho, @abi@)
|
||||||
|
CSRCS += @srcroot@src/zone.c
|
||||||
|
endif
|
||||||
|
STATIC_LIBS := @objroot@lib/libjemalloc@install_suffix@.a
|
||||||
|
DSOS := @objroot@lib/libjemalloc@install_suffix@.$(SO).$(REV) \
|
||||||
|
@objroot@lib/libjemalloc@install_suffix@.$(SO) \
|
||||||
|
@objroot@lib/libjemalloc@install_suffix@_pic.a
|
||||||
|
MAN3 := @objroot@doc/jemalloc@install_suffix@.3
|
||||||
|
DOCS_XML := @objroot@doc/jemalloc@install_suffix@.xml
|
||||||
|
DOCS_HTML := $(DOCS_XML:@objroot@%.xml=@srcroot@%.html)
|
||||||
|
DOCS_MAN3 := $(DOCS_XML:@objroot@%.xml=@srcroot@%.3)
|
||||||
|
DOCS := $(DOCS_HTML) $(DOCS_MAN3)
|
||||||
|
CTESTS := @srcroot@test/allocated.c @srcroot@test/allocm.c \
|
||||||
|
@srcroot@test/bitmap.c @srcroot@test/mremap.c \
|
||||||
|
@srcroot@test/posix_memalign.c @srcroot@test/rallocm.c \
|
||||||
|
@srcroot@test/thread_arena.c
|
||||||
|
|
||||||
|
.PHONY: all dist doc_html doc_man doc
|
||||||
|
.PHONY: install_bin install_include install_lib
|
||||||
|
.PHONY: install_html install_man install_doc install
|
||||||
|
.PHONY: tests check clean distclean relclean
|
||||||
|
|
||||||
|
.SECONDARY : $(CTESTS:@srcroot@%.c=@objroot@%.o)
|
||||||
|
|
||||||
|
# Default target.
|
||||||
|
all: $(DSOS) $(STATIC_LIBS)
|
||||||
|
|
||||||
|
dist: doc
|
||||||
|
|
||||||
|
@srcroot@doc/%.html : @objroot@doc/%.xml @srcroot@doc/stylesheet.xsl @objroot@doc/html.xsl
|
||||||
|
@XSLTPROC@ -o $@ @objroot@doc/html.xsl $<
|
||||||
|
|
||||||
|
@srcroot@doc/%.3 : @objroot@doc/%.xml @srcroot@doc/stylesheet.xsl @objroot@doc/manpages.xsl
|
||||||
|
@XSLTPROC@ -o $@ @objroot@doc/manpages.xsl $<
|
||||||
|
|
||||||
|
doc_html: $(DOCS_HTML)
|
||||||
|
doc_man: $(DOCS_MAN3)
|
||||||
|
doc: $(DOCS)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Include generated dependency files.
|
||||||
|
#
|
||||||
|
-include $(CSRCS:@srcroot@%.c=@objroot@%.d)
|
||||||
|
-include $(CSRCS:@srcroot@%.c=@objroot@%.pic.d)
|
||||||
|
-include $(CTESTS:@srcroot@%.c=@objroot@%.d)
|
||||||
|
|
||||||
|
@objroot@src/%.o: @srcroot@src/%.c
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
$(CC) $(CFLAGS) -c $(CPPFLAGS) -o $@ $<
|
||||||
|
@$(SHELL) -ec "$(CC) -MM $(CPPFLAGS) $< | sed \"s/\($(subst /,\/,$(notdir $(basename $@)))\)\.o\([ :]*\)/$(subst /,\/,$(strip $(dir $@)))\1.o \2/g\" > $(@:%.o=%.d)"
|
||||||
|
|
||||||
|
@objroot@src/%.pic.o: @srcroot@src/%.c
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
$(CC) $(CFLAGS) -fPIC -DPIC -c $(CPPFLAGS) -o $@ $<
|
||||||
|
@$(SHELL) -ec "$(CC) -MM $(CPPFLAGS) $< | sed \"s/\($(subst /,\/,$(notdir $(basename $(basename $@))))\)\.o\([ :]*\)/$(subst /,\/,$(strip $(dir $@)))\1.pic.o \2/g\" > $(@:%.o=%.d)"
|
||||||
|
|
||||||
|
%.$(SO) : %.$(SO).$(REV)
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
ln -sf $(<F) $@
|
||||||
|
|
||||||
|
@objroot@lib/libjemalloc@install_suffix@.$(SO).$(REV) : $(CSRCS:@srcroot@%.c=@objroot@%.pic.o)
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
$(CC) -shared -Wl,-$(WL_SONAME),$(@F) $(RPATH_EXTRA:%=@RPATH@%) -o $@ $+ $(LDFLAGS) $(LIBS)
|
||||||
|
|
||||||
|
@objroot@lib/libjemalloc@install_suffix@_pic.a : $(CSRCS:@srcroot@%.c=@objroot@%.pic.o)
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
ar crus $@ $+
|
||||||
|
|
||||||
|
@objroot@lib/libjemalloc@install_suffix@.a : $(CSRCS:@srcroot@%.c=@objroot@%.o)
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
ar crus $@ $+
|
||||||
|
|
||||||
|
@objroot@test/%.o: @srcroot@test/%.c
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
$(CC) $(CFLAGS) -c $(CPPFLAGS) -I@objroot@test -o $@ $<
|
||||||
|
@$(SHELL) -ec "$(CC) -MM $(CPPFLAGS) -I@objroot@test $< | sed \"s/\($(subst /,\/,$(notdir $(basename $@)))\)\.o\([ :]*\)/$(subst /,\/,$(strip $(dir $@)))\1.o \2/g\" > $(@:%.o=%.d)"
|
||||||
|
|
||||||
|
# Automatic dependency generation misses #include "*.c".
|
||||||
|
@objroot@test/bitmap.o : @objroot@src/bitmap.o
|
||||||
|
|
||||||
|
@objroot@test/%: @objroot@test/%.o \
|
||||||
|
@objroot@lib/libjemalloc@install_suffix@.$(SO)
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
ifneq (@RPATH@, )
|
||||||
|
$(CC) -o $@ $< @RPATH@@objroot@lib -L@objroot@lib -ljemalloc@install_suffix@ -lpthread
|
||||||
|
else
|
||||||
|
$(CC) -o $@ $< -L@objroot@lib -ljemalloc@install_suffix@ -lpthread
|
||||||
|
endif
|
||||||
|
|
||||||
|
install_bin:
|
||||||
|
install -d $(BINDIR)
|
||||||
|
@for b in $(BINS); do \
|
||||||
|
echo "install -m 755 $$b $(BINDIR)"; \
|
||||||
|
install -m 755 $$b $(BINDIR); \
|
||||||
|
done
|
||||||
|
|
||||||
|
install_include:
|
||||||
|
install -d $(INCLUDEDIR)/jemalloc
|
||||||
|
@for h in $(CHDRS); do \
|
||||||
|
echo "install -m 644 $$h $(INCLUDEDIR)/jemalloc"; \
|
||||||
|
install -m 644 $$h $(INCLUDEDIR)/jemalloc; \
|
||||||
|
done
|
||||||
|
|
||||||
|
install_lib: $(DSOS) $(STATIC_LIBS)
|
||||||
|
install -d $(LIBDIR)
|
||||||
|
install -m 755 @objroot@lib/libjemalloc@install_suffix@.$(SO).$(REV) $(LIBDIR)
|
||||||
|
ln -sf libjemalloc@install_suffix@.$(SO).$(REV) $(LIBDIR)/libjemalloc@install_suffix@.$(SO)
|
||||||
|
install -m 755 @objroot@lib/libjemalloc@install_suffix@_pic.a $(LIBDIR)
|
||||||
|
install -m 755 @objroot@lib/libjemalloc@install_suffix@.a $(LIBDIR)
|
||||||
|
|
||||||
|
install_html:
|
||||||
|
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@; \
|
||||||
|
done
|
||||||
|
|
||||||
|
install_man:
|
||||||
|
install -d $(MANDIR)/man3
|
||||||
|
@for d in $(DOCS_MAN3); do \
|
||||||
|
echo "install -m 644 $$d $(MANDIR)/man3"; \
|
||||||
|
install -m 644 $$d $(MANDIR)/man3; \
|
||||||
|
done
|
||||||
|
|
||||||
|
install_doc: install_html install_man
|
||||||
|
|
||||||
|
install: install_bin install_include install_lib install_doc
|
||||||
|
|
||||||
|
tests: $(CTESTS:@srcroot@%.c=@objroot@%)
|
||||||
|
|
||||||
|
check: tests
|
||||||
|
@mkdir -p @objroot@test
|
||||||
|
@$(SHELL) -c 'total=0; \
|
||||||
|
failures=0; \
|
||||||
|
echo "========================================="; \
|
||||||
|
for t in $(CTESTS:@srcroot@%.c=@objroot@%); do \
|
||||||
|
total=`expr $$total + 1`; \
|
||||||
|
/bin/echo -n "$${t} ... "; \
|
||||||
|
$(TEST_LIBRARY_PATH) $${t} @abs_srcroot@ @abs_objroot@ \
|
||||||
|
> @objroot@$${t}.out 2>&1; \
|
||||||
|
if test -e "@srcroot@$${t}.exp"; then \
|
||||||
|
diff -u @srcroot@$${t}.exp \
|
||||||
|
@objroot@$${t}.out >/dev/null 2>&1; \
|
||||||
|
fail=$$?; \
|
||||||
|
if test "$${fail}" -eq "1" ; then \
|
||||||
|
failures=`expr $${failures} + 1`; \
|
||||||
|
echo "*** FAIL ***"; \
|
||||||
|
else \
|
||||||
|
echo "pass"; \
|
||||||
|
fi; \
|
||||||
|
else \
|
||||||
|
echo "*** FAIL *** (.exp file is missing)"; \
|
||||||
|
failures=`expr $${failures} + 1`; \
|
||||||
|
fi; \
|
||||||
|
done; \
|
||||||
|
echo "========================================="; \
|
||||||
|
echo "Failures: $${failures}/$${total}"'
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(CSRCS:@srcroot@%.c=@objroot@%.o)
|
||||||
|
rm -f $(CSRCS:@srcroot@%.c=@objroot@%.pic.o)
|
||||||
|
rm -f $(CSRCS:@srcroot@%.c=@objroot@%.d)
|
||||||
|
rm -f $(CSRCS:@srcroot@%.c=@objroot@%.pic.d)
|
||||||
|
rm -f $(CTESTS:@srcroot@%.c=@objroot@%)
|
||||||
|
rm -f $(CTESTS:@srcroot@%.c=@objroot@%.o)
|
||||||
|
rm -f $(CTESTS:@srcroot@%.c=@objroot@%.d)
|
||||||
|
rm -f $(CTESTS:@srcroot@%.c=@objroot@%.out)
|
||||||
|
rm -f $(DSOS) $(STATIC_LIBS)
|
||||||
|
|
||||||
|
distclean: clean
|
||||||
|
rm -rf @objroot@autom4te.cache
|
||||||
|
rm -f @objroot@config.log
|
||||||
|
rm -f @objroot@config.status
|
||||||
|
rm -f @objroot@config.stamp
|
||||||
|
rm -f @cfghdrs_out@
|
||||||
|
rm -f @cfgoutputs_out@
|
||||||
|
|
||||||
|
relclean: distclean
|
||||||
|
rm -f @objroot@configure
|
||||||
|
rm -f @srcroot@VERSION
|
||||||
|
rm -f $(DOCS_HTML)
|
||||||
|
rm -f $(DOCS_MAN3)
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# Re-configuration rules.
|
||||||
|
|
||||||
|
ifeq (@enable_autogen@, 1)
|
||||||
|
@srcroot@configure : @srcroot@configure.ac
|
||||||
|
cd ./@srcroot@ && @AUTOCONF@
|
||||||
|
|
||||||
|
@objroot@config.status : @srcroot@configure
|
||||||
|
./@objroot@config.status --recheck
|
||||||
|
|
||||||
|
@srcroot@config.stamp.in : @srcroot@configure.ac
|
||||||
|
echo stamp > @srcroot@config.stamp.in
|
||||||
|
|
||||||
|
@objroot@config.stamp : @cfgoutputs_in@ @cfghdrs_in@ @srcroot@configure
|
||||||
|
./@objroot@config.status
|
||||||
|
@touch $@
|
||||||
|
|
||||||
|
# There must be some action in order for make to re-read Makefile when it is
|
||||||
|
# out of date.
|
||||||
|
@cfgoutputs_out@ @cfghdrs_out@ : @objroot@config.stamp
|
||||||
|
@true
|
||||||
|
endif
|
||||||
16
README
Normal file
16
README
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
jemalloc is a general-purpose scalable concurrent malloc(3) implementation.
|
||||||
|
This distribution is a stand-alone "portable" implementation that currently
|
||||||
|
targets Linux and Apple OS X. jemalloc is included as the default allocator in
|
||||||
|
the FreeBSD and NetBSD operating systems, and it is used by the Mozilla Firefox
|
||||||
|
web browser on Microsoft Windows-related platforms. Depending on your needs,
|
||||||
|
one of the other divergent versions may suit your needs better than this
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
The COPYING file contains copyright and licensing information.
|
||||||
|
|
||||||
|
The INSTALL file contains information on how to configure, build, and install
|
||||||
|
jemalloc.
|
||||||
|
|
||||||
|
The ChangeLog file contains a brief summary of changes for each release.
|
||||||
|
|
||||||
|
URL: http://www.canonware.com/jemalloc/
|
||||||
0
jemalloc/config.guess → config.guess
vendored
0
jemalloc/config.guess → config.guess
vendored
0
jemalloc/config.sub → config.sub
vendored
0
jemalloc/config.sub → config.sub
vendored
@@ -80,17 +80,31 @@ MANDIR=`eval echo $mandir`
|
|||||||
MANDIR=`eval echo $MANDIR`
|
MANDIR=`eval echo $MANDIR`
|
||||||
AC_SUBST([MANDIR])
|
AC_SUBST([MANDIR])
|
||||||
|
|
||||||
|
dnl Support for building documentation.
|
||||||
|
AC_PATH_PROG([XSLTPROC], [xsltproc], , [$PATH])
|
||||||
|
AC_ARG_WITH([xslroot],
|
||||||
|
[AS_HELP_STRING([--with-xslroot=<path>], [XSL stylesheet root path])],
|
||||||
|
if test "x$with_xslroot" = "xno" ; then
|
||||||
|
XSLROOT="/usr/share/xml/docbook/stylesheet/docbook-xsl"
|
||||||
|
else
|
||||||
|
XSLROOT="${with_xslroot}"
|
||||||
|
fi,
|
||||||
|
XSLROOT="/usr/share/xml/docbook/stylesheet/docbook-xsl"
|
||||||
|
)
|
||||||
|
AC_SUBST([XSLROOT])
|
||||||
|
|
||||||
dnl If CFLAGS isn't defined, set CFLAGS to something reasonable. Otherwise,
|
dnl If CFLAGS isn't defined, set CFLAGS to something reasonable. Otherwise,
|
||||||
dnl just prevent autoconf from molesting CFLAGS.
|
dnl just prevent autoconf from molesting CFLAGS.
|
||||||
CFLAGS=$CFLAGS
|
CFLAGS=$CFLAGS
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
if test "x$CFLAGS" = "x" ; then
|
if test "x$CFLAGS" = "x" ; then
|
||||||
no_CFLAGS="yes"
|
no_CFLAGS="yes"
|
||||||
JE_CFLAGS_APPEND([-std=gnu99])
|
if test "x$GCC" = "xyes" ; then
|
||||||
JE_CFLAGS_APPEND([-Wall])
|
JE_CFLAGS_APPEND([-std=gnu99])
|
||||||
JE_CFLAGS_APPEND([-pipe])
|
JE_CFLAGS_APPEND([-Wall])
|
||||||
JE_CFLAGS_APPEND([-g3])
|
JE_CFLAGS_APPEND([-pipe])
|
||||||
JE_CFLAGS_APPEND([-march=native])
|
JE_CFLAGS_APPEND([-g3])
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
dnl Append EXTRA_CFLAGS to CFLAGS, if defined.
|
dnl Append EXTRA_CFLAGS to CFLAGS, if defined.
|
||||||
if test "x$EXTRA_CFLAGS" != "x" ; then
|
if test "x$EXTRA_CFLAGS" != "x" ; then
|
||||||
@@ -118,6 +132,16 @@ else
|
|||||||
fi
|
fi
|
||||||
AC_DEFINE_UNQUOTED([LG_SIZEOF_INT], [$LG_SIZEOF_INT])
|
AC_DEFINE_UNQUOTED([LG_SIZEOF_INT], [$LG_SIZEOF_INT])
|
||||||
|
|
||||||
|
AC_CHECK_SIZEOF([long])
|
||||||
|
if test "x${ac_cv_sizeof_long}" = "x8" ; then
|
||||||
|
LG_SIZEOF_LONG=3
|
||||||
|
elif test "x${ac_cv_sizeof_long}" = "x4" ; then
|
||||||
|
LG_SIZEOF_LONG=2
|
||||||
|
else
|
||||||
|
AC_MSG_ERROR([Unsupported long size: ${ac_cv_sizeof_long}])
|
||||||
|
fi
|
||||||
|
AC_DEFINE_UNQUOTED([LG_SIZEOF_LONG], [$LG_SIZEOF_LONG])
|
||||||
|
|
||||||
AC_CANONICAL_HOST
|
AC_CANONICAL_HOST
|
||||||
dnl CPU-specific settings.
|
dnl CPU-specific settings.
|
||||||
CPU_SPINWAIT=""
|
CPU_SPINWAIT=""
|
||||||
@@ -143,17 +167,6 @@ case "${host_cpu}" in
|
|||||||
esac
|
esac
|
||||||
AC_DEFINE_UNQUOTED([CPU_SPINWAIT], [$CPU_SPINWAIT])
|
AC_DEFINE_UNQUOTED([CPU_SPINWAIT], [$CPU_SPINWAIT])
|
||||||
|
|
||||||
JE_COMPILABLE([__attribute__ syntax],
|
|
||||||
[static __attribute__((unused)) void foo(void){}],
|
|
||||||
[],
|
|
||||||
[attribute])
|
|
||||||
if test "x${attribute}" = "xyes" ; then
|
|
||||||
AC_DEFINE([JEMALLOC_HAVE_ATTR], [ ])
|
|
||||||
if test "x$GCC" = "xyes" ; then
|
|
||||||
JE_CFLAGS_APPEND([-fvisibility=internal])
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
dnl Platform-specific settings. abi and RPATH can probably be determined
|
dnl Platform-specific settings. abi and RPATH can probably be determined
|
||||||
dnl programmatically, but doing so is error-prone, which makes it generally
|
dnl programmatically, but doing so is error-prone, which makes it generally
|
||||||
dnl not worth the trouble.
|
dnl not worth the trouble.
|
||||||
@@ -165,17 +178,20 @@ case "${host}" in
|
|||||||
*-*-darwin*)
|
*-*-darwin*)
|
||||||
CFLAGS="$CFLAGS -fno-common -no-cpp-precomp"
|
CFLAGS="$CFLAGS -fno-common -no-cpp-precomp"
|
||||||
abi="macho"
|
abi="macho"
|
||||||
|
AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE])
|
||||||
RPATH=""
|
RPATH=""
|
||||||
;;
|
;;
|
||||||
*-*-freebsd*)
|
*-*-freebsd*)
|
||||||
CFLAGS="$CFLAGS"
|
CFLAGS="$CFLAGS"
|
||||||
abi="elf"
|
abi="elf"
|
||||||
|
AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE])
|
||||||
RPATH="-Wl,-rpath,"
|
RPATH="-Wl,-rpath,"
|
||||||
;;
|
;;
|
||||||
*-*-linux*)
|
*-*-linux*)
|
||||||
CFLAGS="$CFLAGS"
|
CFLAGS="$CFLAGS"
|
||||||
CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE"
|
CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE"
|
||||||
abi="elf"
|
abi="elf"
|
||||||
|
AC_DEFINE([JEMALLOC_PURGE_MADVISE_DONTNEED])
|
||||||
RPATH="-Wl,-rpath,"
|
RPATH="-Wl,-rpath,"
|
||||||
;;
|
;;
|
||||||
*-*-netbsd*)
|
*-*-netbsd*)
|
||||||
@@ -190,6 +206,7 @@ case "${host}" in
|
|||||||
[CFLAGS="$CFLAGS"; abi="elf"],
|
[CFLAGS="$CFLAGS"; abi="elf"],
|
||||||
[abi="aout"])
|
[abi="aout"])
|
||||||
AC_MSG_RESULT([$abi])
|
AC_MSG_RESULT([$abi])
|
||||||
|
AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE])
|
||||||
RPATH="-Wl,-rpath,"
|
RPATH="-Wl,-rpath,"
|
||||||
;;
|
;;
|
||||||
*-*-solaris2*)
|
*-*-solaris2*)
|
||||||
@@ -209,6 +226,27 @@ esac
|
|||||||
AC_SUBST([abi])
|
AC_SUBST([abi])
|
||||||
AC_SUBST([RPATH])
|
AC_SUBST([RPATH])
|
||||||
|
|
||||||
|
JE_COMPILABLE([__attribute__ syntax],
|
||||||
|
[static __attribute__((unused)) void foo(void){}],
|
||||||
|
[],
|
||||||
|
[attribute])
|
||||||
|
if test "x${attribute}" = "xyes" ; then
|
||||||
|
AC_DEFINE([JEMALLOC_HAVE_ATTR], [ ])
|
||||||
|
if test "x${GCC}" = "xyes" -a "x${abi}" = "xelf"; then
|
||||||
|
JE_CFLAGS_APPEND([-fvisibility=hidden])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
JE_COMPILABLE([mremap(...MREMAP_FIXED...)], [
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <sys/mman.h>
|
||||||
|
], [
|
||||||
|
void *p = mremap((void *)0, 0, 0, MREMAP_MAYMOVE|MREMAP_FIXED, (void *)0);
|
||||||
|
], [mremap_fixed])
|
||||||
|
if test "x${mremap_fixed}" = "xyes" ; then
|
||||||
|
AC_DEFINE([JEMALLOC_MREMAP_FIXED])
|
||||||
|
fi
|
||||||
|
|
||||||
dnl Support optional additions to rpath.
|
dnl Support optional additions to rpath.
|
||||||
AC_ARG_WITH([rpath],
|
AC_ARG_WITH([rpath],
|
||||||
[AS_HELP_STRING([--with-rpath=<rpath>], [Colon-separated rpath (ELF systems only)])],
|
[AS_HELP_STRING([--with-rpath=<rpath>], [Colon-separated rpath (ELF systems only)])],
|
||||||
@@ -244,15 +282,32 @@ dnl Do not prefix public APIs by default.
|
|||||||
AC_ARG_WITH([jemalloc_prefix],
|
AC_ARG_WITH([jemalloc_prefix],
|
||||||
[AS_HELP_STRING([--with-jemalloc-prefix=<prefix>], [Prefix to prepend to all public APIs])],
|
[AS_HELP_STRING([--with-jemalloc-prefix=<prefix>], [Prefix to prepend to all public APIs])],
|
||||||
[JEMALLOC_PREFIX="$with_jemalloc_prefix"],
|
[JEMALLOC_PREFIX="$with_jemalloc_prefix"],
|
||||||
[JEMALLOC_PREFIX=]
|
[if test "x$abi" != "xmacho" ; then
|
||||||
|
JEMALLOC_PREFIX=""
|
||||||
|
else
|
||||||
|
JEMALLOC_PREFIX="je_"
|
||||||
|
fi]
|
||||||
)
|
)
|
||||||
if test "x$JEMALLOC_PREFIX" != "x" ; then
|
if test "x$JEMALLOC_PREFIX" != "x" ; then
|
||||||
AC_DEFINE([JEMALLOC_PREFIX], [ ])
|
JEMALLOC_CPREFIX=`echo ${JEMALLOC_PREFIX} | tr "a-z" "A-Z"`
|
||||||
jemalloc_prefix="$JEMALLOC_PREFIX"
|
AC_DEFINE_UNQUOTED([JEMALLOC_PREFIX], ["$JEMALLOC_PREFIX"])
|
||||||
AC_SUBST([jemalloc_prefix])
|
AC_DEFINE_UNQUOTED([JEMALLOC_CPREFIX], ["$JEMALLOC_CPREFIX"])
|
||||||
AC_DEFINE_UNQUOTED([JEMALLOC_P(string_that_no_one_should_want_to_use_as_a_jemalloc_API_prefix)], [${JEMALLOC_PREFIX}##string_that_no_one_should_want_to_use_as_a_jemalloc_API_prefix])
|
AC_DEFINE_UNQUOTED([JEMALLOC_P(string_that_no_one_should_want_to_use_as_a_jemalloc_API_prefix)], [${JEMALLOC_PREFIX}##string_that_no_one_should_want_to_use_as_a_jemalloc_API_prefix])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
dnl Do not mangle library-private APIs by default.
|
||||||
|
AC_ARG_WITH([private_namespace],
|
||||||
|
[AS_HELP_STRING([--with-private-namespace=<prefix>], [Prefix to prepend to all library-private APIs])],
|
||||||
|
[JEMALLOC_PRIVATE_NAMESPACE="$with_private_namespace"],
|
||||||
|
[JEMALLOC_PRIVATE_NAMESPACE=""]
|
||||||
|
)
|
||||||
|
AC_DEFINE_UNQUOTED([JEMALLOC_PRIVATE_NAMESPACE], ["$JEMALLOC_PRIVATE_NAMESPACE"])
|
||||||
|
if test "x$JEMALLOC_PRIVATE_NAMESPACE" != "x" ; then
|
||||||
|
AC_DEFINE_UNQUOTED([JEMALLOC_N(string_that_no_one_should_want_to_use_as_a_jemalloc_private_namespace_prefix)], [${JEMALLOC_PRIVATE_NAMESPACE}##string_that_no_one_should_want_to_use_as_a_jemalloc_private_namespace_prefix])
|
||||||
|
else
|
||||||
|
AC_DEFINE_UNQUOTED([JEMALLOC_N(string_that_no_one_should_want_to_use_as_a_jemalloc_private_namespace_prefix)], [string_that_no_one_should_want_to_use_as_a_jemalloc_private_namespace_prefix])
|
||||||
|
fi
|
||||||
|
|
||||||
dnl Do not add suffix to installed files by default.
|
dnl Do not add suffix to installed files by default.
|
||||||
AC_ARG_WITH([install_suffix],
|
AC_ARG_WITH([install_suffix],
|
||||||
[AS_HELP_STRING([--with-install-suffix=<suffix>], [Suffix to append to all installed files])],
|
[AS_HELP_STRING([--with-install-suffix=<suffix>], [Suffix to append to all installed files])],
|
||||||
@@ -262,24 +317,53 @@ AC_ARG_WITH([install_suffix],
|
|||||||
install_suffix="$INSTALL_SUFFIX"
|
install_suffix="$INSTALL_SUFFIX"
|
||||||
AC_SUBST([install_suffix])
|
AC_SUBST([install_suffix])
|
||||||
|
|
||||||
cfgoutputs_in="Makefile doc/jemalloc.3.in"
|
cfgoutputs_in="${srcroot}Makefile.in"
|
||||||
cfgoutputs_in="${cfgoutputs_in} include/jemalloc/jemalloc.h.in"
|
cfgoutputs_in="${cfgoutputs_in} ${srcroot}doc/html.xsl.in"
|
||||||
cfgoutputs_in="${cfgoutputs_in} include/jemalloc/internal/jemalloc_internal.h.in"
|
cfgoutputs_in="${cfgoutputs_in} ${srcroot}doc/manpages.xsl.in"
|
||||||
|
cfgoutputs_in="${cfgoutputs_in} ${srcroot}doc/jemalloc.xml.in"
|
||||||
|
cfgoutputs_in="${cfgoutputs_in} ${srcroot}include/jemalloc/jemalloc.h.in"
|
||||||
|
cfgoutputs_in="${cfgoutputs_in} ${srcroot}include/jemalloc/internal/jemalloc_internal.h.in"
|
||||||
|
cfgoutputs_in="${cfgoutputs_in} ${srcroot}test/jemalloc_test.h.in"
|
||||||
|
|
||||||
cfgoutputs_out="Makefile doc/jemalloc${install_suffix}.3"
|
cfgoutputs_out="Makefile"
|
||||||
|
cfgoutputs_out="${cfgoutputs_out} doc/html.xsl"
|
||||||
|
cfgoutputs_out="${cfgoutputs_out} doc/manpages.xsl"
|
||||||
|
cfgoutputs_out="${cfgoutputs_out} doc/jemalloc${install_suffix}.xml"
|
||||||
cfgoutputs_out="${cfgoutputs_out} include/jemalloc/jemalloc${install_suffix}.h"
|
cfgoutputs_out="${cfgoutputs_out} include/jemalloc/jemalloc${install_suffix}.h"
|
||||||
cfgoutputs_out="${cfgoutputs_out} include/jemalloc/internal/jemalloc_internal.h"
|
cfgoutputs_out="${cfgoutputs_out} include/jemalloc/internal/jemalloc_internal.h"
|
||||||
|
cfgoutputs_out="${cfgoutputs_out} test/jemalloc_test.h"
|
||||||
|
|
||||||
cfgoutputs_tup="Makefile doc/jemalloc${install_suffix}.3:doc/jemalloc.3.in"
|
cfgoutputs_tup="Makefile"
|
||||||
|
cfgoutputs_tup="${cfgoutputs_tup} doc/html.xsl:doc/html.xsl.in"
|
||||||
|
cfgoutputs_tup="${cfgoutputs_tup} doc/manpages.xsl:doc/manpages.xsl.in"
|
||||||
|
cfgoutputs_tup="${cfgoutputs_tup} doc/jemalloc${install_suffix}.xml:doc/jemalloc.xml.in"
|
||||||
cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/jemalloc${install_suffix}.h:include/jemalloc/jemalloc.h.in"
|
cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/jemalloc${install_suffix}.h:include/jemalloc/jemalloc.h.in"
|
||||||
cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/internal/jemalloc_internal.h"
|
cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/internal/jemalloc_internal.h"
|
||||||
|
cfgoutputs_tup="${cfgoutputs_tup} test/jemalloc_test.h:test/jemalloc_test.h.in"
|
||||||
|
|
||||||
cfghdrs_in="include/jemalloc/jemalloc_defs.h.in"
|
cfghdrs_in="${srcroot}include/jemalloc/jemalloc_defs.h.in"
|
||||||
|
|
||||||
cfghdrs_out="include/jemalloc/jemalloc_defs${install_suffix}.h"
|
cfghdrs_out="include/jemalloc/jemalloc_defs${install_suffix}.h"
|
||||||
|
|
||||||
cfghdrs_tup="include/jemalloc/jemalloc_defs${install_suffix}.h:include/jemalloc/jemalloc_defs.h.in"
|
cfghdrs_tup="include/jemalloc/jemalloc_defs${install_suffix}.h:include/jemalloc/jemalloc_defs.h.in"
|
||||||
|
|
||||||
|
dnl Do not silence irrelevant compiler warnings by default, since enabling this
|
||||||
|
dnl option incurs a performance penalty.
|
||||||
|
AC_ARG_ENABLE([cc-silence],
|
||||||
|
[AS_HELP_STRING([--enable-cc-silence],
|
||||||
|
[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="0"]
|
||||||
|
)
|
||||||
|
if test "x$enable_cc_silence" = "x1" ; then
|
||||||
|
AC_DEFINE([JEMALLOC_CC_SILENCE])
|
||||||
|
fi
|
||||||
|
|
||||||
dnl Do not compile with debugging by default.
|
dnl Do not compile with debugging by default.
|
||||||
AC_ARG_ENABLE([debug],
|
AC_ARG_ENABLE([debug],
|
||||||
[AS_HELP_STRING([--enable-debug], [Build debugging code])],
|
[AS_HELP_STRING([--enable-debug], [Build debugging code])],
|
||||||
@@ -293,6 +377,7 @@ fi
|
|||||||
)
|
)
|
||||||
if test "x$enable_debug" = "x1" ; then
|
if test "x$enable_debug" = "x1" ; then
|
||||||
AC_DEFINE([JEMALLOC_DEBUG], [ ])
|
AC_DEFINE([JEMALLOC_DEBUG], [ ])
|
||||||
|
AC_DEFINE([JEMALLOC_IVSALLOC], [ ])
|
||||||
fi
|
fi
|
||||||
AC_SUBST([enable_debug])
|
AC_SUBST([enable_debug])
|
||||||
|
|
||||||
@@ -305,7 +390,6 @@ if test "x$enable_debug" = "x0" -a "x$no_CFLAGS" = "xyes" ; then
|
|||||||
if test "x$GCC" = "xyes" ; then
|
if test "x$GCC" = "xyes" ; then
|
||||||
JE_CFLAGS_APPEND([-O3])
|
JE_CFLAGS_APPEND([-O3])
|
||||||
JE_CFLAGS_APPEND([-funroll-loops])
|
JE_CFLAGS_APPEND([-funroll-loops])
|
||||||
JE_CFLAGS_APPEND([-fomit-frame-pointer])
|
|
||||||
else
|
else
|
||||||
JE_CFLAGS_APPEND([-O])
|
JE_CFLAGS_APPEND([-O])
|
||||||
fi
|
fi
|
||||||
@@ -327,12 +411,6 @@ if test "x$enable_stats" = "x1" ; then
|
|||||||
AC_DEFINE([JEMALLOC_STATS], [ ])
|
AC_DEFINE([JEMALLOC_STATS], [ ])
|
||||||
fi
|
fi
|
||||||
AC_SUBST([enable_stats])
|
AC_SUBST([enable_stats])
|
||||||
if test "x$enable_stats" = "x0" ; then
|
|
||||||
roff_stats=".\\\" "
|
|
||||||
else
|
|
||||||
roff_stats=""
|
|
||||||
fi
|
|
||||||
AC_SUBST([roff_stats])
|
|
||||||
|
|
||||||
dnl Do not enable profiling by default.
|
dnl Do not enable profiling by default.
|
||||||
AC_ARG_ENABLE([prof],
|
AC_ARG_ENABLE([prof],
|
||||||
@@ -345,6 +423,49 @@ fi
|
|||||||
],
|
],
|
||||||
[enable_prof="0"]
|
[enable_prof="0"]
|
||||||
)
|
)
|
||||||
|
if test "x$enable_prof" = "x1" ; then
|
||||||
|
backtrace_method=""
|
||||||
|
else
|
||||||
|
backtrace_method="N/A"
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_ARG_ENABLE([prof-libunwind],
|
||||||
|
[AS_HELP_STRING([--enable-prof-libunwind], [Use libunwind for backtracing])],
|
||||||
|
[if test "x$enable_prof_libunwind" = "xno" ; then
|
||||||
|
enable_prof_libunwind="0"
|
||||||
|
else
|
||||||
|
enable_prof_libunwind="1"
|
||||||
|
fi
|
||||||
|
],
|
||||||
|
[enable_prof_libunwind="0"]
|
||||||
|
)
|
||||||
|
AC_ARG_WITH([static_libunwind],
|
||||||
|
[AS_HELP_STRING([--with-static-libunwind=<libunwind.a>],
|
||||||
|
[Path to static libunwind library; use rather than dynamically linking])],
|
||||||
|
if test "x$with_static_libunwind" = "xno" ; then
|
||||||
|
LUNWIND="-lunwind"
|
||||||
|
else
|
||||||
|
if test ! -f "$with_static_libunwind" ; then
|
||||||
|
AC_MSG_ERROR([Static libunwind not found: $with_static_libunwind])
|
||||||
|
fi
|
||||||
|
LUNWIND="$with_static_libunwind"
|
||||||
|
fi,
|
||||||
|
LUNWIND="-lunwind"
|
||||||
|
)
|
||||||
|
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], [backtrace], [LIBS="$LIBS $LUNWIND"],
|
||||||
|
[enable_prof_libunwind="0"])
|
||||||
|
else
|
||||||
|
LIBS="$LIBS $LUNWIND"
|
||||||
|
fi
|
||||||
|
if test "x${enable_prof_libunwind}" = "x1" ; then
|
||||||
|
backtrace_method="libunwind"
|
||||||
|
AC_DEFINE([JEMALLOC_PROF_LIBUNWIND], [ ])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
AC_ARG_ENABLE([prof-libgcc],
|
AC_ARG_ENABLE([prof-libgcc],
|
||||||
[AS_HELP_STRING([--disable-prof-libgcc],
|
[AS_HELP_STRING([--disable-prof-libgcc],
|
||||||
[Do not use libgcc for backtracing])],
|
[Do not use libgcc for backtracing])],
|
||||||
@@ -356,17 +477,64 @@ fi
|
|||||||
],
|
],
|
||||||
[enable_prof_libgcc="1"]
|
[enable_prof_libgcc="1"]
|
||||||
)
|
)
|
||||||
AC_ARG_ENABLE([prof-libunwind],
|
if test "x$backtrace_method" = "x" -a "x$enable_prof_libgcc" = "x1" \
|
||||||
[AS_HELP_STRING([--enable-prof-libunwind], [Use libunwind for backtracing])],
|
-a "x$GCC" = "xyes" ; then
|
||||||
[if test "x$enable_prof_libunwind" = "xno" ; then
|
AC_CHECK_HEADERS([unwind.h], , [enable_prof_libgcc="0"])
|
||||||
enable_prof_libunwind="0"
|
AC_CHECK_LIB([gcc], [_Unwind_Backtrace], [LIBS="$LIBS -lgcc"], [enable_prof_libgcc="0"])
|
||||||
|
dnl The following is conservative, in that it only has entries for CPUs on
|
||||||
|
dnl which jemalloc has been tested.
|
||||||
|
AC_MSG_CHECKING([libgcc-based backtracing reliability on ${host_cpu}])
|
||||||
|
case "${host_cpu}" in
|
||||||
|
i[[3456]]86)
|
||||||
|
AC_MSG_RESULT([unreliable])
|
||||||
|
enable_prof_libgcc="0";
|
||||||
|
;;
|
||||||
|
x86_64)
|
||||||
|
AC_MSG_RESULT([reliable])
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
AC_MSG_RESULT([unreliable])
|
||||||
|
enable_prof_libgcc="0";
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
if test "x${enable_prof_libgcc}" = "x1" ; then
|
||||||
|
backtrace_method="libgcc"
|
||||||
|
AC_DEFINE([JEMALLOC_PROF_LIBGCC], [ ])
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
enable_prof_libunwind="1"
|
enable_prof_libgcc="0"
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_ARG_ENABLE([prof-gcc],
|
||||||
|
[AS_HELP_STRING([--disable-prof-gcc],
|
||||||
|
[Do not use gcc intrinsics for backtracing])],
|
||||||
|
[if test "x$enable_prof_gcc" = "xno" ; then
|
||||||
|
enable_prof_gcc="0"
|
||||||
|
else
|
||||||
|
enable_prof_gcc="1"
|
||||||
fi
|
fi
|
||||||
],
|
],
|
||||||
[enable_prof_libunwind="0"]
|
[enable_prof_gcc="1"]
|
||||||
)
|
)
|
||||||
dnl Finish prof-related definitions below, once TLS configuration is done.
|
if test "x$backtrace_method" = "x" -a "x$enable_prof_gcc" = "x1" \
|
||||||
|
-a "x$GCC" = "xyes" ; then
|
||||||
|
backtrace_method="gcc intrinsics"
|
||||||
|
AC_DEFINE([JEMALLOC_PROF_GCC], [ ])
|
||||||
|
else
|
||||||
|
enable_prof_gcc="0"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "x$backtrace_method" = "x" ; then
|
||||||
|
backtrace_method="none (disabling profiling)"
|
||||||
|
enable_prof="0"
|
||||||
|
fi
|
||||||
|
AC_MSG_CHECKING([configured backtracing method])
|
||||||
|
AC_MSG_RESULT([$backtrace_method])
|
||||||
|
if test "x$enable_prof" = "x1" ; then
|
||||||
|
LIBS="$LIBS -lm"
|
||||||
|
AC_DEFINE([JEMALLOC_PROF], [ ])
|
||||||
|
fi
|
||||||
|
AC_SUBST([enable_prof])
|
||||||
|
|
||||||
dnl Enable tiny allocations by default.
|
dnl Enable tiny allocations by default.
|
||||||
AC_ARG_ENABLE([tiny],
|
AC_ARG_ENABLE([tiny],
|
||||||
@@ -383,15 +551,6 @@ if test "x$enable_tiny" = "x1" ; then
|
|||||||
AC_DEFINE([JEMALLOC_TINY], [ ])
|
AC_DEFINE([JEMALLOC_TINY], [ ])
|
||||||
fi
|
fi
|
||||||
AC_SUBST([enable_tiny])
|
AC_SUBST([enable_tiny])
|
||||||
if test "x$enable_tiny" = "x0" ; then
|
|
||||||
roff_tiny=".\\\" "
|
|
||||||
roff_no_tiny=""
|
|
||||||
else
|
|
||||||
roff_tiny=""
|
|
||||||
roff_no_tiny=".\\\" "
|
|
||||||
fi
|
|
||||||
AC_SUBST([roff_tiny])
|
|
||||||
AC_SUBST([roff_no_tiny])
|
|
||||||
|
|
||||||
dnl Enable thread-specific caching by default.
|
dnl Enable thread-specific caching by default.
|
||||||
AC_ARG_ENABLE([tcache],
|
AC_ARG_ENABLE([tcache],
|
||||||
@@ -404,7 +563,10 @@ fi
|
|||||||
],
|
],
|
||||||
[enable_tcache="1"]
|
[enable_tcache="1"]
|
||||||
)
|
)
|
||||||
dnl Finish tcache-related definitions below, once TLS configuration is done.
|
if test "x$enable_tcache" = "x1" ; then
|
||||||
|
AC_DEFINE([JEMALLOC_TCACHE], [ ])
|
||||||
|
fi
|
||||||
|
AC_SUBST([enable_tcache])
|
||||||
|
|
||||||
dnl Do not enable mmap()ped swap files by default.
|
dnl Do not enable mmap()ped swap files by default.
|
||||||
AC_ARG_ENABLE([swap],
|
AC_ARG_ENABLE([swap],
|
||||||
@@ -421,12 +583,6 @@ if test "x$enable_swap" = "x1" ; then
|
|||||||
AC_DEFINE([JEMALLOC_SWAP], [ ])
|
AC_DEFINE([JEMALLOC_SWAP], [ ])
|
||||||
fi
|
fi
|
||||||
AC_SUBST([enable_swap])
|
AC_SUBST([enable_swap])
|
||||||
if test "x$enable_swap" = "x0" ; then
|
|
||||||
roff_swap=".\\\" "
|
|
||||||
else
|
|
||||||
roff_swap=""
|
|
||||||
fi
|
|
||||||
AC_SUBST([roff_swap])
|
|
||||||
|
|
||||||
dnl Do not enable allocation from DSS by default.
|
dnl Do not enable allocation from DSS by default.
|
||||||
AC_ARG_ENABLE([dss],
|
AC_ARG_ENABLE([dss],
|
||||||
@@ -443,12 +599,6 @@ if test "x$enable_dss" = "x1" ; then
|
|||||||
AC_DEFINE([JEMALLOC_DSS], [ ])
|
AC_DEFINE([JEMALLOC_DSS], [ ])
|
||||||
fi
|
fi
|
||||||
AC_SUBST([enable_dss])
|
AC_SUBST([enable_dss])
|
||||||
if test "x$enable_dss" = "x0" ; then
|
|
||||||
roff_dss=".\\\" "
|
|
||||||
else
|
|
||||||
roff_dss=""
|
|
||||||
fi
|
|
||||||
AC_SUBST([roff_dss])
|
|
||||||
|
|
||||||
dnl Do not support the junk/zero filling option by default.
|
dnl Do not support the junk/zero filling option by default.
|
||||||
AC_ARG_ENABLE([fill],
|
AC_ARG_ENABLE([fill],
|
||||||
@@ -465,12 +615,6 @@ if test "x$enable_fill" = "x1" ; then
|
|||||||
AC_DEFINE([JEMALLOC_FILL], [ ])
|
AC_DEFINE([JEMALLOC_FILL], [ ])
|
||||||
fi
|
fi
|
||||||
AC_SUBST([enable_fill])
|
AC_SUBST([enable_fill])
|
||||||
if test "x$enable_fill" = "x0" ; then
|
|
||||||
roff_fill=".\\\" "
|
|
||||||
else
|
|
||||||
roff_fill=""
|
|
||||||
fi
|
|
||||||
AC_SUBST([roff_fill])
|
|
||||||
|
|
||||||
dnl Do not support the xmalloc option by default.
|
dnl Do not support the xmalloc option by default.
|
||||||
AC_ARG_ENABLE([xmalloc],
|
AC_ARG_ENABLE([xmalloc],
|
||||||
@@ -487,12 +631,6 @@ if test "x$enable_xmalloc" = "x1" ; then
|
|||||||
AC_DEFINE([JEMALLOC_XMALLOC], [ ])
|
AC_DEFINE([JEMALLOC_XMALLOC], [ ])
|
||||||
fi
|
fi
|
||||||
AC_SUBST([enable_xmalloc])
|
AC_SUBST([enable_xmalloc])
|
||||||
if test "x$enable_xmalloc" = "x0" ; then
|
|
||||||
roff_xmalloc=".\\\" "
|
|
||||||
else
|
|
||||||
roff_xmalloc=""
|
|
||||||
fi
|
|
||||||
AC_SUBST([roff_xmalloc])
|
|
||||||
|
|
||||||
dnl Do not support the SYSV option by default.
|
dnl Do not support the SYSV option by default.
|
||||||
AC_ARG_ENABLE([sysv],
|
AC_ARG_ENABLE([sysv],
|
||||||
@@ -509,12 +647,6 @@ if test "x$enable_sysv" = "x1" ; then
|
|||||||
AC_DEFINE([JEMALLOC_SYSV], [ ])
|
AC_DEFINE([JEMALLOC_SYSV], [ ])
|
||||||
fi
|
fi
|
||||||
AC_SUBST([enable_sysv])
|
AC_SUBST([enable_sysv])
|
||||||
if test "x$enable_sysv" = "x0" ; then
|
|
||||||
roff_sysv=".\\\" "
|
|
||||||
else
|
|
||||||
roff_sysv=""
|
|
||||||
fi
|
|
||||||
AC_SUBST([roff_sysv])
|
|
||||||
|
|
||||||
dnl Do not determine page shift at run time by default.
|
dnl Do not determine page shift at run time by default.
|
||||||
AC_ARG_ENABLE([dynamic_page_shift],
|
AC_ARG_ENABLE([dynamic_page_shift],
|
||||||
@@ -565,8 +697,8 @@ dnl jemalloc configuration.
|
|||||||
dnl
|
dnl
|
||||||
|
|
||||||
dnl Set VERSION if source directory has an embedded git repository.
|
dnl Set VERSION if source directory has an embedded git repository.
|
||||||
if test -d "${srcroot}../.git" ; then
|
if test -d "${srcroot}.git" ; then
|
||||||
git describe --long > ${srcroot}VERSION
|
git describe --long --abbrev=40 > ${srcroot}VERSION
|
||||||
fi
|
fi
|
||||||
jemalloc_version=`cat ${srcroot}VERSION`
|
jemalloc_version=`cat ${srcroot}VERSION`
|
||||||
jemalloc_version_major=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]1}'`
|
jemalloc_version_major=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]1}'`
|
||||||
@@ -634,65 +766,108 @@ AC_RUN_IFELSE([AC_LANG_PROGRAM(
|
|||||||
AC_MSG_RESULT([no])
|
AC_MSG_RESULT([no])
|
||||||
enable_tls="0")
|
enable_tls="0")
|
||||||
fi
|
fi
|
||||||
|
AC_SUBST([enable_tls])
|
||||||
if test "x${enable_tls}" = "x0" ; then
|
if test "x${enable_tls}" = "x0" ; then
|
||||||
AC_DEFINE_UNQUOTED([NO_TLS], [ ])
|
AC_DEFINE_UNQUOTED([NO_TLS], [ ])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dnl Finish tcache-related definitions, now that TLS configuration is done.
|
dnl ============================================================================
|
||||||
if test "x$enable_tls" = "x0" ; then
|
dnl Check for ffsl(3), and fail if not found. This function exists on all
|
||||||
enable_tcache="0"
|
dnl platforms that jemalloc currently has a chance of functioning on without
|
||||||
fi
|
dnl modification.
|
||||||
if test "x$enable_tcache" = "x1" ; then
|
|
||||||
AC_DEFINE([JEMALLOC_TCACHE], [ ])
|
|
||||||
fi
|
|
||||||
AC_SUBST([enable_tcache])
|
|
||||||
if test "x$enable_tcache" = "x0" ; then
|
|
||||||
roff_tcache=".\\\" "
|
|
||||||
roff_no_tcache=""
|
|
||||||
else
|
|
||||||
roff_tcache=""
|
|
||||||
roff_no_tcache=".\\\" "
|
|
||||||
fi
|
|
||||||
AC_SUBST([roff_tcache])
|
|
||||||
AC_SUBST([roff_no_tcache])
|
|
||||||
|
|
||||||
dnl Finish prof-related definitions, now that TLS configuration is done.
|
AC_CHECK_FUNC([ffsl], [],
|
||||||
if test "x$enable_tls" = "x0" ; then
|
[AC_MSG_ERROR([Cannot build without ffsl(3)])])
|
||||||
enable_prof="0"
|
|
||||||
fi
|
|
||||||
if test "x$enable_prof" = "x1" ; then
|
|
||||||
LIBS="$LIBS -lm"
|
|
||||||
AC_DEFINE([JEMALLOC_PROF], [ ])
|
|
||||||
if test "x$enable_prof_libunwind" = "x1" ; then
|
|
||||||
AC_CHECK_HEADERS([libunwind.h], , [enable_prof_libunwind="0"])
|
|
||||||
AC_CHECK_LIB([unwind], [backtrace], [LIBS="$LIBS -lunwind"],
|
|
||||||
[enable_prof_libunwind="0"])
|
|
||||||
if test "x${enable_prof_libunwind}" = "x1" ; then
|
|
||||||
AC_DEFINE([JEMALLOC_PROF_LIBUNWIND], [ ])
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
AC_SUBST([enable_prof])
|
|
||||||
if test "x$enable_prof" = "x0" ; then
|
|
||||||
roff_prof=".\\\" "
|
|
||||||
roff_no_prof=""
|
|
||||||
else
|
|
||||||
roff_prof=""
|
|
||||||
roff_no_prof=".\\\" "
|
|
||||||
fi
|
|
||||||
AC_SUBST([roff_prof])
|
|
||||||
AC_SUBST([roff_no_prof])
|
|
||||||
|
|
||||||
dnl If libunwind isn't enabled, try to use libgcc rather than gcc intrinsics
|
dnl ============================================================================
|
||||||
dnl for backtracing.
|
dnl Check for atomic(3) operations as provided on Darwin.
|
||||||
if test "x$enable_prof" = "x1" -a "x$enable_prof_libunwind" = "x0" \
|
|
||||||
-a "x$GCC" = "xyes" -a "x$enable_prof_libgcc" = "x1" ; then
|
JE_COMPILABLE([Darwin OSAtomic*()], [
|
||||||
enable_prof_libgcc="1"
|
#include <libkern/OSAtomic.h>
|
||||||
AC_CHECK_HEADERS([unwind.h], , [enable_prof_libgcc="0"])
|
#include <inttypes.h>
|
||||||
AC_CHECK_LIB([gcc], [_Unwind_Backtrace], [LIBS="$LIBS -lgcc"], [enable_prof_libgcc="0"])
|
], [
|
||||||
if test "x${enable_prof_libgcc}" = "x1" ; then
|
{
|
||||||
AC_DEFINE([JEMALLOC_PROF_LIBGCC], [ ])
|
int32_t x32 = 0;
|
||||||
fi
|
volatile int32_t *x32p = &x32;
|
||||||
|
OSAtomicAdd32(1, x32p);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int64_t x64 = 0;
|
||||||
|
volatile int64_t *x64p = &x64;
|
||||||
|
OSAtomicAdd64(1, x64p);
|
||||||
|
}
|
||||||
|
], [osatomic])
|
||||||
|
if test "x${osatomic}" = "xyes" ; then
|
||||||
|
AC_DEFINE([JEMALLOC_OSATOMIC])
|
||||||
|
fi
|
||||||
|
|
||||||
|
dnl ============================================================================
|
||||||
|
dnl Check for spinlock(3) operations as provided on Darwin.
|
||||||
|
|
||||||
|
JE_COMPILABLE([Darwin OSSpin*()], [
|
||||||
|
#include <libkern/OSAtomic.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
], [
|
||||||
|
OSSpinLock lock = 0;
|
||||||
|
OSSpinLockLock(&lock);
|
||||||
|
OSSpinLockUnlock(&lock);
|
||||||
|
], [osspin])
|
||||||
|
if test "x${osspin}" = "xyes" ; then
|
||||||
|
AC_DEFINE([JEMALLOC_OSSPIN])
|
||||||
|
fi
|
||||||
|
|
||||||
|
dnl ============================================================================
|
||||||
|
dnl Check for allocator-related functions that should be wrapped.
|
||||||
|
|
||||||
|
AC_CHECK_FUNC([memalign],
|
||||||
|
[AC_DEFINE([JEMALLOC_OVERRIDE_MEMALIGN])])
|
||||||
|
AC_CHECK_FUNC([valloc],
|
||||||
|
[AC_DEFINE([JEMALLOC_OVERRIDE_VALLOC])])
|
||||||
|
|
||||||
|
dnl ============================================================================
|
||||||
|
dnl Darwin-related configuration.
|
||||||
|
|
||||||
|
if test "x${abi}" = "xmacho" ; then
|
||||||
|
AC_DEFINE([JEMALLOC_IVSALLOC])
|
||||||
|
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_TRY_COMPILE([#include <stdlib.h>
|
||||||
|
#include <malloc/malloc.h>], [
|
||||||
|
static malloc_zone_t zone;
|
||||||
|
static struct malloc_introspection_t zone_introspect;
|
||||||
|
|
||||||
|
zone.size = NULL;
|
||||||
|
zone.malloc = NULL;
|
||||||
|
zone.calloc = NULL;
|
||||||
|
zone.valloc = NULL;
|
||||||
|
zone.free = NULL;
|
||||||
|
zone.realloc = NULL;
|
||||||
|
zone.destroy = NULL;
|
||||||
|
zone.zone_name = "jemalloc_zone";
|
||||||
|
zone.batch_malloc = NULL;
|
||||||
|
zone.batch_free = NULL;
|
||||||
|
zone.introspect = &zone_introspect;
|
||||||
|
zone.version = 6;
|
||||||
|
zone.memalign = NULL;
|
||||||
|
zone.free_definite_size = NULL;
|
||||||
|
|
||||||
|
zone_introspect.enumerator = NULL;
|
||||||
|
zone_introspect.good_size = NULL;
|
||||||
|
zone_introspect.check = NULL;
|
||||||
|
zone_introspect.print = NULL;
|
||||||
|
zone_introspect.log = NULL;
|
||||||
|
zone_introspect.force_lock = NULL;
|
||||||
|
zone_introspect.force_unlock = NULL;
|
||||||
|
zone_introspect.statistics = NULL;
|
||||||
|
zone_introspect.zone_locked = NULL;
|
||||||
|
], [AC_DEFINE_UNQUOTED([JEMALLOC_ZONE_VERSION], [6])
|
||||||
|
AC_MSG_RESULT([6])],
|
||||||
|
[AC_DEFINE_UNQUOTED([JEMALLOC_ZONE_VERSION], [3])
|
||||||
|
AC_MSG_RESULT([3])])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dnl ============================================================================
|
dnl ============================================================================
|
||||||
@@ -702,11 +877,11 @@ AC_HEADER_STDBOOL
|
|||||||
dnl Process .in files.
|
dnl Process .in files.
|
||||||
AC_SUBST([cfghdrs_in])
|
AC_SUBST([cfghdrs_in])
|
||||||
AC_SUBST([cfghdrs_out])
|
AC_SUBST([cfghdrs_out])
|
||||||
AC_CONFIG_HEADERS([$cfghdrs_tup cfghdrs.stamp])
|
AC_CONFIG_HEADERS([$cfghdrs_tup])
|
||||||
|
|
||||||
dnl ============================================================================
|
dnl ============================================================================
|
||||||
dnl Generate outputs.
|
dnl Generate outputs.
|
||||||
AC_CONFIG_FILES([$cfgoutputs_tup cfgoutputs.stamp])
|
AC_CONFIG_FILES([$cfgoutputs_tup config.stamp])
|
||||||
AC_SUBST([cfgoutputs_in])
|
AC_SUBST([cfgoutputs_in])
|
||||||
AC_SUBST([cfgoutputs_out])
|
AC_SUBST([cfgoutputs_out])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
@@ -723,6 +898,9 @@ AC_MSG_RESULT([LDFLAGS : ${LDFLAGS}])
|
|||||||
AC_MSG_RESULT([LIBS : ${LIBS}])
|
AC_MSG_RESULT([LIBS : ${LIBS}])
|
||||||
AC_MSG_RESULT([RPATH_EXTRA : ${RPATH_EXTRA}])
|
AC_MSG_RESULT([RPATH_EXTRA : ${RPATH_EXTRA}])
|
||||||
AC_MSG_RESULT([])
|
AC_MSG_RESULT([])
|
||||||
|
AC_MSG_RESULT([XSLTPROC : ${XSLTPROC}])
|
||||||
|
AC_MSG_RESULT([XSLROOT : ${XSLROOT}])
|
||||||
|
AC_MSG_RESULT([])
|
||||||
AC_MSG_RESULT([PREFIX : ${PREFIX}])
|
AC_MSG_RESULT([PREFIX : ${PREFIX}])
|
||||||
AC_MSG_RESULT([BINDIR : ${BINDIR}])
|
AC_MSG_RESULT([BINDIR : ${BINDIR}])
|
||||||
AC_MSG_RESULT([INCLUDEDIR : ${INCLUDEDIR}])
|
AC_MSG_RESULT([INCLUDEDIR : ${INCLUDEDIR}])
|
||||||
@@ -736,12 +914,17 @@ AC_MSG_RESULT([objroot : ${objroot}])
|
|||||||
AC_MSG_RESULT([abs_objroot : ${abs_objroot}])
|
AC_MSG_RESULT([abs_objroot : ${abs_objroot}])
|
||||||
AC_MSG_RESULT([])
|
AC_MSG_RESULT([])
|
||||||
AC_MSG_RESULT([JEMALLOC_PREFIX : ${JEMALLOC_PREFIX}])
|
AC_MSG_RESULT([JEMALLOC_PREFIX : ${JEMALLOC_PREFIX}])
|
||||||
|
AC_MSG_RESULT([JEMALLOC_PRIVATE_NAMESPACE])
|
||||||
|
AC_MSG_RESULT([ : ${JEMALLOC_PRIVATE_NAMESPACE}])
|
||||||
AC_MSG_RESULT([install_suffix : ${install_suffix}])
|
AC_MSG_RESULT([install_suffix : ${install_suffix}])
|
||||||
AC_MSG_RESULT([autogen : ${enable_autogen}])
|
AC_MSG_RESULT([autogen : ${enable_autogen}])
|
||||||
|
AC_MSG_RESULT([cc-silence : ${enable_cc_silence}])
|
||||||
AC_MSG_RESULT([debug : ${enable_debug}])
|
AC_MSG_RESULT([debug : ${enable_debug}])
|
||||||
AC_MSG_RESULT([stats : ${enable_stats}])
|
AC_MSG_RESULT([stats : ${enable_stats}])
|
||||||
AC_MSG_RESULT([prof : ${enable_prof}])
|
AC_MSG_RESULT([prof : ${enable_prof}])
|
||||||
AC_MSG_RESULT([prof-libunwind : ${enable_prof_libunwind}])
|
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([tiny : ${enable_tiny}])
|
AC_MSG_RESULT([tiny : ${enable_tiny}])
|
||||||
AC_MSG_RESULT([tcache : ${enable_tcache}])
|
AC_MSG_RESULT([tcache : ${enable_tcache}])
|
||||||
AC_MSG_RESULT([fill : ${enable_fill}])
|
AC_MSG_RESULT([fill : ${enable_fill}])
|
||||||
@@ -751,4 +934,5 @@ AC_MSG_RESULT([swap : ${enable_swap}])
|
|||||||
AC_MSG_RESULT([dss : ${enable_dss}])
|
AC_MSG_RESULT([dss : ${enable_dss}])
|
||||||
AC_MSG_RESULT([dynamic_page_shift : ${enable_dynamic_page_shift}])
|
AC_MSG_RESULT([dynamic_page_shift : ${enable_dynamic_page_shift}])
|
||||||
AC_MSG_RESULT([lazy_lock : ${enable_lazy_lock}])
|
AC_MSG_RESULT([lazy_lock : ${enable_lazy_lock}])
|
||||||
|
AC_MSG_RESULT([tls : ${enable_tls}])
|
||||||
AC_MSG_RESULT([===============================================================================])
|
AC_MSG_RESULT([===============================================================================])
|
||||||
4
doc/html.xsl.in
Normal file
4
doc/html.xsl.in
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
|
||||||
|
<xsl:import href="@XSLROOT@/html/docbook.xsl"/>
|
||||||
|
<xsl:import href="@abs_srcroot@doc/stylesheet.xsl"/>
|
||||||
|
</xsl:stylesheet>
|
||||||
2280
doc/jemalloc.xml.in
Normal file
2280
doc/jemalloc.xml.in
Normal file
File diff suppressed because it is too large
Load Diff
4
doc/manpages.xsl.in
Normal file
4
doc/manpages.xsl.in
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
|
||||||
|
<xsl:import href="@XSLROOT@/manpages/docbook.xsl"/>
|
||||||
|
<xsl:import href="@abs_srcroot@doc/stylesheet.xsl"/>
|
||||||
|
</xsl:stylesheet>
|
||||||
7
doc/stylesheet.xsl
Normal file
7
doc/stylesheet.xsl
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
|
||||||
|
<xsl:param name="funcsynopsis.style">ansi</xsl:param>
|
||||||
|
<xsl:param name="function.parens" select="1"/>
|
||||||
|
<xsl:template match="mallctl">
|
||||||
|
"<xsl:call-template name="inline.monoseq"/>"
|
||||||
|
</xsl:template>
|
||||||
|
</xsl:stylesheet>
|
||||||
743
include/jemalloc/internal/arena.h
Normal file
743
include/jemalloc/internal/arena.h
Normal file
@@ -0,0 +1,743 @@
|
|||||||
|
/******************************************************************************/
|
||||||
|
#ifdef JEMALLOC_H_TYPES
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Subpages are an artificially designated partitioning of pages. Their only
|
||||||
|
* purpose is to support subpage-spaced size classes.
|
||||||
|
*
|
||||||
|
* There must be at least 4 subpages per page, due to the way size classes are
|
||||||
|
* handled.
|
||||||
|
*/
|
||||||
|
#define LG_SUBPAGE 8
|
||||||
|
#define SUBPAGE ((size_t)(1U << LG_SUBPAGE))
|
||||||
|
#define SUBPAGE_MASK (SUBPAGE - 1)
|
||||||
|
|
||||||
|
/* Return the smallest subpage multiple that is >= s. */
|
||||||
|
#define SUBPAGE_CEILING(s) \
|
||||||
|
(((s) + SUBPAGE_MASK) & ~SUBPAGE_MASK)
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_TINY
|
||||||
|
/* Smallest size class to support. */
|
||||||
|
# define LG_TINY_MIN LG_SIZEOF_PTR
|
||||||
|
# define TINY_MIN (1U << LG_TINY_MIN)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maximum size class that is a multiple of the quantum, but not (necessarily)
|
||||||
|
* a power of 2. Above this size, allocations are rounded up to the nearest
|
||||||
|
* power of 2.
|
||||||
|
*/
|
||||||
|
#define LG_QSPACE_MAX_DEFAULT 7
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maximum size class that is a multiple of the cacheline, but not (necessarily)
|
||||||
|
* a power of 2. Above this size, allocations are rounded up to the nearest
|
||||||
|
* power of 2.
|
||||||
|
*/
|
||||||
|
#define LG_CSPACE_MAX_DEFAULT 9
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RUN_MAX_OVRHD indicates maximum desired run header overhead. Runs are sized
|
||||||
|
* as small as possible such that this setting is still honored, without
|
||||||
|
* violating other constraints. The goal is to make runs as small as possible
|
||||||
|
* without exceeding a per run external fragmentation threshold.
|
||||||
|
*
|
||||||
|
* We use binary fixed point math for overhead computations, where the binary
|
||||||
|
* point is implicitly RUN_BFP bits to the left.
|
||||||
|
*
|
||||||
|
* Note that it is possible to set RUN_MAX_OVRHD low enough that it cannot be
|
||||||
|
* honored for some/all object sizes, since when heap profiling is enabled
|
||||||
|
* there is one pointer of header overhead per object (plus a constant). This
|
||||||
|
* constraint is relaxed (ignored) for runs that are so small that the
|
||||||
|
* per-region overhead is greater than:
|
||||||
|
*
|
||||||
|
* (RUN_MAX_OVRHD / (reg_size << (3+RUN_BFP))
|
||||||
|
*/
|
||||||
|
#define RUN_BFP 12
|
||||||
|
/* \/ Implicit binary fixed point. */
|
||||||
|
#define RUN_MAX_OVRHD 0x0000003dU
|
||||||
|
#define RUN_MAX_OVRHD_RELAX 0x00001800U
|
||||||
|
|
||||||
|
/* Maximum number of regions in one run. */
|
||||||
|
#define LG_RUN_MAXREGS 11
|
||||||
|
#define RUN_MAXREGS (1U << LG_RUN_MAXREGS)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The minimum ratio of active:dirty pages per arena is computed as:
|
||||||
|
*
|
||||||
|
* (nactive >> opt_lg_dirty_mult) >= ndirty
|
||||||
|
*
|
||||||
|
* So, supposing that opt_lg_dirty_mult is 5, there can be no less than 32
|
||||||
|
* times as many active pages as dirty pages.
|
||||||
|
*/
|
||||||
|
#define LG_DIRTY_MULT_DEFAULT 5
|
||||||
|
|
||||||
|
typedef struct arena_chunk_map_s arena_chunk_map_t;
|
||||||
|
typedef struct arena_chunk_s arena_chunk_t;
|
||||||
|
typedef struct arena_run_s arena_run_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;
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_TYPES */
|
||||||
|
/******************************************************************************/
|
||||||
|
#ifdef JEMALLOC_H_STRUCTS
|
||||||
|
|
||||||
|
/* Each element of the chunk map corresponds to one page within the chunk. */
|
||||||
|
struct arena_chunk_map_s {
|
||||||
|
union {
|
||||||
|
/*
|
||||||
|
* Linkage for run trees. There are two disjoint uses:
|
||||||
|
*
|
||||||
|
* 1) arena_t's runs_avail_{clean,dirty} trees.
|
||||||
|
* 2) arena_run_t conceptually uses this linkage for in-use
|
||||||
|
* non-full runs, rather than directly embedding linkage.
|
||||||
|
*/
|
||||||
|
rb_node(arena_chunk_map_t) rb_link;
|
||||||
|
/*
|
||||||
|
* List of runs currently in purgatory. arena_chunk_purge()
|
||||||
|
* temporarily allocates runs that contain dirty pages while
|
||||||
|
* purging, so that other threads cannot use the runs while the
|
||||||
|
* purging thread is operating without the arena lock held.
|
||||||
|
*/
|
||||||
|
ql_elm(arena_chunk_map_t) ql_link;
|
||||||
|
} u;
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_PROF
|
||||||
|
/* Profile counters, used for large object runs. */
|
||||||
|
prof_ctx_t *prof_ctx;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Run address (or size) and various flags are stored together. The bit
|
||||||
|
* layout looks like (assuming 32-bit system):
|
||||||
|
*
|
||||||
|
* ???????? ???????? ????---- ----dula
|
||||||
|
*
|
||||||
|
* ? : Unallocated: Run address for first/last pages, unset for internal
|
||||||
|
* pages.
|
||||||
|
* Small: Run page offset.
|
||||||
|
* Large: Run size for first page, unset for trailing pages.
|
||||||
|
* - : Unused.
|
||||||
|
* d : dirty?
|
||||||
|
* u : unzeroed?
|
||||||
|
* l : large?
|
||||||
|
* a : allocated?
|
||||||
|
*
|
||||||
|
* Following are example bit patterns for the three types of runs.
|
||||||
|
*
|
||||||
|
* p : run page offset
|
||||||
|
* s : run size
|
||||||
|
* c : (binind+1) for size class (used only if prof_promote is true)
|
||||||
|
* x : don't care
|
||||||
|
* - : 0
|
||||||
|
* + : 1
|
||||||
|
* [DULA] : bit set
|
||||||
|
* [dula] : bit unset
|
||||||
|
*
|
||||||
|
* Unallocated (clean):
|
||||||
|
* ssssssss ssssssss ssss---- ----du-a
|
||||||
|
* xxxxxxxx xxxxxxxx xxxx---- -----Uxx
|
||||||
|
* ssssssss ssssssss ssss---- ----dU-a
|
||||||
|
*
|
||||||
|
* Unallocated (dirty):
|
||||||
|
* ssssssss ssssssss ssss---- ----D--a
|
||||||
|
* xxxxxxxx xxxxxxxx xxxx---- ----xxxx
|
||||||
|
* ssssssss ssssssss ssss---- ----D--a
|
||||||
|
*
|
||||||
|
* Small:
|
||||||
|
* pppppppp pppppppp pppp---- ----d--A
|
||||||
|
* pppppppp pppppppp pppp---- -------A
|
||||||
|
* pppppppp pppppppp pppp---- ----d--A
|
||||||
|
*
|
||||||
|
* Large:
|
||||||
|
* ssssssss ssssssss ssss---- ----D-LA
|
||||||
|
* xxxxxxxx xxxxxxxx xxxx---- ----xxxx
|
||||||
|
* -------- -------- -------- ----D-LA
|
||||||
|
*
|
||||||
|
* Large (sampled, size <= PAGE_SIZE):
|
||||||
|
* ssssssss ssssssss sssscccc ccccD-LA
|
||||||
|
*
|
||||||
|
* Large (not sampled, size == PAGE_SIZE):
|
||||||
|
* ssssssss ssssssss ssss---- ----D-LA
|
||||||
|
*/
|
||||||
|
size_t bits;
|
||||||
|
#ifdef JEMALLOC_PROF
|
||||||
|
#define CHUNK_MAP_CLASS_SHIFT 4
|
||||||
|
#define CHUNK_MAP_CLASS_MASK ((size_t)0xff0U)
|
||||||
|
#endif
|
||||||
|
#define CHUNK_MAP_FLAGS_MASK ((size_t)0xfU)
|
||||||
|
#define CHUNK_MAP_DIRTY ((size_t)0x8U)
|
||||||
|
#define CHUNK_MAP_UNZEROED ((size_t)0x4U)
|
||||||
|
#define CHUNK_MAP_LARGE ((size_t)0x2U)
|
||||||
|
#define CHUNK_MAP_ALLOCATED ((size_t)0x1U)
|
||||||
|
#define CHUNK_MAP_KEY CHUNK_MAP_ALLOCATED
|
||||||
|
};
|
||||||
|
typedef rb_tree(arena_chunk_map_t) arena_avail_tree_t;
|
||||||
|
typedef rb_tree(arena_chunk_map_t) arena_run_tree_t;
|
||||||
|
|
||||||
|
/* Arena chunk header. */
|
||||||
|
struct arena_chunk_s {
|
||||||
|
/* Arena that owns the chunk. */
|
||||||
|
arena_t *arena;
|
||||||
|
|
||||||
|
/* Linkage for the arena's chunks_dirty list. */
|
||||||
|
ql_elm(arena_chunk_t) link_dirty;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* True if the chunk is currently in the chunks_dirty list, due to
|
||||||
|
* having at some point contained one or more dirty pages. Removal
|
||||||
|
* from chunks_dirty is lazy, so (dirtied && ndirty == 0) is possible.
|
||||||
|
*/
|
||||||
|
bool dirtied;
|
||||||
|
|
||||||
|
/* Number of dirty pages. */
|
||||||
|
size_t ndirty;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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_t map[1]; /* Dynamically sized. */
|
||||||
|
};
|
||||||
|
typedef rb_tree(arena_chunk_t) arena_chunk_tree_t;
|
||||||
|
|
||||||
|
struct arena_run_s {
|
||||||
|
#ifdef JEMALLOC_DEBUG
|
||||||
|
uint32_t magic;
|
||||||
|
# define ARENA_RUN_MAGIC 0x384adf93
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Bin this run is associated with. */
|
||||||
|
arena_bin_t *bin;
|
||||||
|
|
||||||
|
/* Index of next region that has never been allocated, or nregs. */
|
||||||
|
uint32_t nextind;
|
||||||
|
|
||||||
|
/* Number of free regions in run. */
|
||||||
|
unsigned nfree;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
struct arena_bin_info_s {
|
||||||
|
/* Size of regions in a run 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 number of regions in a run for this bin's size class. */
|
||||||
|
uint32_t nregs;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Offset of first bitmap_t element in a run header for this bin's size
|
||||||
|
* class.
|
||||||
|
*/
|
||||||
|
uint32_t bitmap_offset;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Metadata used to manipulate bitmaps for runs associated with this
|
||||||
|
* bin.
|
||||||
|
*/
|
||||||
|
bitmap_info_t bitmap_info;
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_PROF
|
||||||
|
/*
|
||||||
|
* Offset of first (prof_ctx_t *) in a run header for this bin's size
|
||||||
|
* class, or 0 if (opt_prof == false).
|
||||||
|
*/
|
||||||
|
uint32_t ctx0_offset;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Offset of first region in a run for this bin's size class. */
|
||||||
|
uint32_t reg0_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
malloc_mutex_t lock;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Current run being used to service allocations of this bin's size
|
||||||
|
* class.
|
||||||
|
*/
|
||||||
|
arena_run_t *runcur;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tree of non-full runs. This tree 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.
|
||||||
|
*/
|
||||||
|
arena_run_tree_t runs;
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
/* Bin statistics. */
|
||||||
|
malloc_bin_stats_t stats;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct arena_s {
|
||||||
|
#ifdef JEMALLOC_DEBUG
|
||||||
|
uint32_t magic;
|
||||||
|
# define ARENA_MAGIC 0x947d3d24
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* This arena's index within the arenas array. */
|
||||||
|
unsigned ind;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Number of threads currently assigned to this arena. This field is
|
||||||
|
* protected by arenas_lock.
|
||||||
|
*/
|
||||||
|
unsigned nthreads;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There are three classes of arena operations from a locking
|
||||||
|
* perspective:
|
||||||
|
* 1) Thread asssignment (modifies nthreads) is protected by
|
||||||
|
* arenas_lock.
|
||||||
|
* 2) Bin-related operations are protected by bin locks.
|
||||||
|
* 3) Chunk- and run-related operations are protected by this mutex.
|
||||||
|
*/
|
||||||
|
malloc_mutex_t lock;
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
arena_stats_t stats;
|
||||||
|
# ifdef JEMALLOC_TCACHE
|
||||||
|
/*
|
||||||
|
* List of tcaches for extant threads associated with this arena.
|
||||||
|
* Stats from these are merged incrementally, and at exit.
|
||||||
|
*/
|
||||||
|
ql_head(tcache_t) tcache_ql;
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_PROF
|
||||||
|
uint64_t prof_accumbytes;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* List of dirty-page-containing chunks this arena manages. */
|
||||||
|
ql_head(arena_chunk_t) chunks_dirty;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
arena_chunk_t *spare;
|
||||||
|
|
||||||
|
/* Number of pages in active runs. */
|
||||||
|
size_t nactive;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Current count of pages within unused runs 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.
|
||||||
|
*/
|
||||||
|
size_t ndirty;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Approximate number of pages being purged. It is possible for
|
||||||
|
* multiple threads to purge dirty pages concurrently, and they use
|
||||||
|
* npurgatory to indicate the total number of pages all threads are
|
||||||
|
* attempting to purge.
|
||||||
|
*/
|
||||||
|
size_t npurgatory;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Size/address-ordered trees of this arena's available runs. The trees
|
||||||
|
* are used for first-best-fit run allocation. The dirty tree contains
|
||||||
|
* runs with dirty pages (i.e. very likely to have been touched and
|
||||||
|
* therefore have associated physical pages), whereas the clean tree
|
||||||
|
* contains runs with pages that either have no associated physical
|
||||||
|
* pages, or have pages that the kernel may recycle at any time due to
|
||||||
|
* previous madvise(2) calls. The dirty tree is used in preference to
|
||||||
|
* the clean tree for allocations, because using dirty pages reduces
|
||||||
|
* the amount of dirty purging necessary to keep the active:dirty page
|
||||||
|
* ratio below the purge threshold.
|
||||||
|
*/
|
||||||
|
arena_avail_tree_t runs_avail_clean;
|
||||||
|
arena_avail_tree_t runs_avail_dirty;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bins is used to store trees of free regions of the following sizes,
|
||||||
|
* assuming a 64-bit system with 16-byte quantum, 4 KiB page size, and
|
||||||
|
* default MALLOC_CONF.
|
||||||
|
*
|
||||||
|
* bins[i] | size |
|
||||||
|
* --------+--------+
|
||||||
|
* 0 | 8 |
|
||||||
|
* --------+--------+
|
||||||
|
* 1 | 16 |
|
||||||
|
* 2 | 32 |
|
||||||
|
* 3 | 48 |
|
||||||
|
* : :
|
||||||
|
* 6 | 96 |
|
||||||
|
* 7 | 112 |
|
||||||
|
* 8 | 128 |
|
||||||
|
* --------+--------+
|
||||||
|
* 9 | 192 |
|
||||||
|
* 10 | 256 |
|
||||||
|
* 11 | 320 |
|
||||||
|
* 12 | 384 |
|
||||||
|
* 13 | 448 |
|
||||||
|
* 14 | 512 |
|
||||||
|
* --------+--------+
|
||||||
|
* 15 | 768 |
|
||||||
|
* 16 | 1024 |
|
||||||
|
* 17 | 1280 |
|
||||||
|
* : :
|
||||||
|
* 25 | 3328 |
|
||||||
|
* 26 | 3584 |
|
||||||
|
* 27 | 3840 |
|
||||||
|
* --------+--------+
|
||||||
|
*/
|
||||||
|
arena_bin_t bins[1]; /* Dynamically sized. */
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_STRUCTS */
|
||||||
|
/******************************************************************************/
|
||||||
|
#ifdef JEMALLOC_H_EXTERNS
|
||||||
|
|
||||||
|
extern size_t opt_lg_qspace_max;
|
||||||
|
extern size_t opt_lg_cspace_max;
|
||||||
|
extern ssize_t opt_lg_dirty_mult;
|
||||||
|
/*
|
||||||
|
* small_size2bin 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 the SMALL_SIZE2BIN macro.
|
||||||
|
*/
|
||||||
|
extern uint8_t const *small_size2bin;
|
||||||
|
#define SMALL_SIZE2BIN(s) (small_size2bin[(s-1) >> LG_TINY_MIN])
|
||||||
|
|
||||||
|
extern arena_bin_info_t *arena_bin_info;
|
||||||
|
|
||||||
|
/* Various bin-related settings. */
|
||||||
|
#ifdef JEMALLOC_TINY /* Number of (2^n)-spaced tiny bins. */
|
||||||
|
# define ntbins ((unsigned)(LG_QUANTUM - LG_TINY_MIN))
|
||||||
|
#else
|
||||||
|
# define ntbins 0
|
||||||
|
#endif
|
||||||
|
extern unsigned nqbins; /* Number of quantum-spaced bins. */
|
||||||
|
extern unsigned ncbins; /* Number of cacheline-spaced bins. */
|
||||||
|
extern unsigned nsbins; /* Number of subpage-spaced bins. */
|
||||||
|
extern unsigned nbins;
|
||||||
|
#ifdef JEMALLOC_TINY
|
||||||
|
# define tspace_max ((size_t)(QUANTUM >> 1))
|
||||||
|
#endif
|
||||||
|
#define qspace_min QUANTUM
|
||||||
|
extern size_t qspace_max;
|
||||||
|
extern size_t cspace_min;
|
||||||
|
extern size_t cspace_max;
|
||||||
|
extern size_t sspace_min;
|
||||||
|
extern size_t sspace_max;
|
||||||
|
#define small_maxclass sspace_max
|
||||||
|
|
||||||
|
#define nlclasses (chunk_npages - map_bias)
|
||||||
|
|
||||||
|
void arena_purge_all(arena_t *arena);
|
||||||
|
#ifdef JEMALLOC_PROF
|
||||||
|
void arena_prof_accum(arena_t *arena, uint64_t accumbytes);
|
||||||
|
#endif
|
||||||
|
#ifdef JEMALLOC_TCACHE
|
||||||
|
void arena_tcache_fill_small(arena_t *arena, tcache_bin_t *tbin,
|
||||||
|
size_t binind
|
||||||
|
# ifdef JEMALLOC_PROF
|
||||||
|
, uint64_t prof_accumbytes
|
||||||
|
# endif
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
void *arena_malloc_small(arena_t *arena, size_t size, bool zero);
|
||||||
|
void *arena_malloc_large(arena_t *arena, size_t size, bool zero);
|
||||||
|
void *arena_malloc(size_t size, bool zero);
|
||||||
|
void *arena_palloc(arena_t *arena, size_t size, size_t alloc_size,
|
||||||
|
size_t alignment, bool zero);
|
||||||
|
size_t arena_salloc(const void *ptr);
|
||||||
|
#ifdef JEMALLOC_PROF
|
||||||
|
void arena_prof_promoted(const void *ptr, size_t size);
|
||||||
|
size_t arena_salloc_demote(const void *ptr);
|
||||||
|
#endif
|
||||||
|
void arena_dalloc_bin(arena_t *arena, arena_chunk_t *chunk, void *ptr,
|
||||||
|
arena_chunk_map_t *mapelm);
|
||||||
|
void arena_dalloc_large(arena_t *arena, arena_chunk_t *chunk, void *ptr);
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
void arena_stats_merge(arena_t *arena, size_t *nactive, size_t *ndirty,
|
||||||
|
arena_stats_t *astats, malloc_bin_stats_t *bstats,
|
||||||
|
malloc_large_stats_t *lstats);
|
||||||
|
#endif
|
||||||
|
void *arena_ralloc_no_move(void *ptr, size_t oldsize, size_t size,
|
||||||
|
size_t extra, bool zero);
|
||||||
|
void *arena_ralloc(void *ptr, size_t oldsize, size_t size, size_t extra,
|
||||||
|
size_t alignment, bool zero);
|
||||||
|
bool arena_new(arena_t *arena, unsigned ind);
|
||||||
|
bool arena_boot(void);
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_EXTERNS */
|
||||||
|
/******************************************************************************/
|
||||||
|
#ifdef JEMALLOC_H_INLINES
|
||||||
|
|
||||||
|
#ifndef JEMALLOC_ENABLE_INLINE
|
||||||
|
size_t arena_bin_index(arena_t *arena, arena_bin_t *bin);
|
||||||
|
unsigned arena_run_regind(arena_run_t *run, arena_bin_info_t *bin_info,
|
||||||
|
const void *ptr);
|
||||||
|
# ifdef JEMALLOC_PROF
|
||||||
|
prof_ctx_t *arena_prof_ctx_get(const void *ptr);
|
||||||
|
void arena_prof_ctx_set(const void *ptr, prof_ctx_t *ctx);
|
||||||
|
# endif
|
||||||
|
void arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_))
|
||||||
|
JEMALLOC_INLINE size_t
|
||||||
|
arena_bin_index(arena_t *arena, arena_bin_t *bin)
|
||||||
|
{
|
||||||
|
size_t binind = bin - arena->bins;
|
||||||
|
assert(binind < nbins);
|
||||||
|
return (binind);
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE unsigned
|
||||||
|
arena_run_regind(arena_run_t *run, arena_bin_info_t *bin_info, const void *ptr)
|
||||||
|
{
|
||||||
|
unsigned shift, diff, regind;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
dassert(run->magic == ARENA_RUN_MAGIC);
|
||||||
|
/*
|
||||||
|
* Freeing a pointer lower than region zero can cause assertion
|
||||||
|
* failure.
|
||||||
|
*/
|
||||||
|
assert((uintptr_t)ptr >= (uintptr_t)run +
|
||||||
|
(uintptr_t)bin_info->reg0_offset);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Avoid doing division with a variable divisor if possible. Using
|
||||||
|
* actual division here can reduce allocator throughput by over 20%!
|
||||||
|
*/
|
||||||
|
diff = (unsigned)((uintptr_t)ptr - (uintptr_t)run -
|
||||||
|
bin_info->reg0_offset);
|
||||||
|
|
||||||
|
/* Rescale (factor powers of 2 out of the numerator and denominator). */
|
||||||
|
size = bin_info->reg_size;
|
||||||
|
shift = ffs(size) - 1;
|
||||||
|
diff >>= shift;
|
||||||
|
size >>= shift;
|
||||||
|
|
||||||
|
if (size == 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 * size_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(unsigned) << 3) - LG_RUN_MAXREGS)
|
||||||
|
#define SIZE_INV(s) (((1U << SIZE_INV_SHIFT) / (s)) + 1)
|
||||||
|
static const unsigned size_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 (size <= ((sizeof(size_invs) / sizeof(unsigned)) + 2))
|
||||||
|
regind = (diff * size_invs[size - 3]) >> SIZE_INV_SHIFT;
|
||||||
|
else
|
||||||
|
regind = diff / size;
|
||||||
|
#undef SIZE_INV
|
||||||
|
#undef SIZE_INV_SHIFT
|
||||||
|
}
|
||||||
|
assert(diff == regind * size);
|
||||||
|
assert(regind < bin_info->nregs);
|
||||||
|
|
||||||
|
return (regind);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_PROF
|
||||||
|
JEMALLOC_INLINE prof_ctx_t *
|
||||||
|
arena_prof_ctx_get(const void *ptr)
|
||||||
|
{
|
||||||
|
prof_ctx_t *ret;
|
||||||
|
arena_chunk_t *chunk;
|
||||||
|
size_t pageind, mapbits;
|
||||||
|
|
||||||
|
assert(ptr != NULL);
|
||||||
|
assert(CHUNK_ADDR2BASE(ptr) != ptr);
|
||||||
|
|
||||||
|
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
||||||
|
pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT;
|
||||||
|
mapbits = chunk->map[pageind-map_bias].bits;
|
||||||
|
assert((mapbits & CHUNK_MAP_ALLOCATED) != 0);
|
||||||
|
if ((mapbits & CHUNK_MAP_LARGE) == 0) {
|
||||||
|
if (prof_promote)
|
||||||
|
ret = (prof_ctx_t *)(uintptr_t)1U;
|
||||||
|
else {
|
||||||
|
arena_run_t *run = (arena_run_t *)((uintptr_t)chunk +
|
||||||
|
(uintptr_t)((pageind - (mapbits >> PAGE_SHIFT)) <<
|
||||||
|
PAGE_SHIFT));
|
||||||
|
size_t binind = arena_bin_index(chunk->arena, run->bin);
|
||||||
|
arena_bin_info_t *bin_info = &arena_bin_info[binind];
|
||||||
|
unsigned regind;
|
||||||
|
|
||||||
|
dassert(run->magic == ARENA_RUN_MAGIC);
|
||||||
|
regind = arena_run_regind(run, bin_info, ptr);
|
||||||
|
ret = *(prof_ctx_t **)((uintptr_t)run +
|
||||||
|
bin_info->ctx0_offset + (regind *
|
||||||
|
sizeof(prof_ctx_t *)));
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
ret = chunk->map[pageind-map_bias].prof_ctx;
|
||||||
|
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE void
|
||||||
|
arena_prof_ctx_set(const void *ptr, prof_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
arena_chunk_t *chunk;
|
||||||
|
size_t pageind, mapbits;
|
||||||
|
|
||||||
|
assert(ptr != NULL);
|
||||||
|
assert(CHUNK_ADDR2BASE(ptr) != ptr);
|
||||||
|
|
||||||
|
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
||||||
|
pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT;
|
||||||
|
mapbits = chunk->map[pageind-map_bias].bits;
|
||||||
|
assert((mapbits & CHUNK_MAP_ALLOCATED) != 0);
|
||||||
|
if ((mapbits & CHUNK_MAP_LARGE) == 0) {
|
||||||
|
if (prof_promote == false) {
|
||||||
|
arena_run_t *run = (arena_run_t *)((uintptr_t)chunk +
|
||||||
|
(uintptr_t)((pageind - (mapbits >> PAGE_SHIFT)) <<
|
||||||
|
PAGE_SHIFT));
|
||||||
|
arena_bin_t *bin = run->bin;
|
||||||
|
size_t binind;
|
||||||
|
arena_bin_info_t *bin_info;
|
||||||
|
unsigned regind;
|
||||||
|
|
||||||
|
dassert(run->magic == ARENA_RUN_MAGIC);
|
||||||
|
binind = arena_bin_index(chunk->arena, bin);
|
||||||
|
bin_info = &arena_bin_info[binind];
|
||||||
|
regind = arena_run_regind(run, bin_info, ptr);
|
||||||
|
|
||||||
|
*((prof_ctx_t **)((uintptr_t)run + bin_info->ctx0_offset
|
||||||
|
+ (regind * sizeof(prof_ctx_t *)))) = ctx;
|
||||||
|
} else
|
||||||
|
assert((uintptr_t)ctx == (uintptr_t)1U);
|
||||||
|
} else
|
||||||
|
chunk->map[pageind-map_bias].prof_ctx = ctx;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
JEMALLOC_INLINE void
|
||||||
|
arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr)
|
||||||
|
{
|
||||||
|
size_t pageind;
|
||||||
|
arena_chunk_map_t *mapelm;
|
||||||
|
|
||||||
|
assert(arena != NULL);
|
||||||
|
dassert(arena->magic == ARENA_MAGIC);
|
||||||
|
assert(chunk->arena == arena);
|
||||||
|
assert(ptr != NULL);
|
||||||
|
assert(CHUNK_ADDR2BASE(ptr) != ptr);
|
||||||
|
|
||||||
|
pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT;
|
||||||
|
mapelm = &chunk->map[pageind-map_bias];
|
||||||
|
assert((mapelm->bits & CHUNK_MAP_ALLOCATED) != 0);
|
||||||
|
if ((mapelm->bits & CHUNK_MAP_LARGE) == 0) {
|
||||||
|
/* Small allocation. */
|
||||||
|
#ifdef JEMALLOC_TCACHE
|
||||||
|
tcache_t *tcache;
|
||||||
|
|
||||||
|
if ((tcache = tcache_get()) != NULL)
|
||||||
|
tcache_dalloc_small(tcache, ptr);
|
||||||
|
else {
|
||||||
|
#endif
|
||||||
|
arena_run_t *run;
|
||||||
|
arena_bin_t *bin;
|
||||||
|
|
||||||
|
run = (arena_run_t *)((uintptr_t)chunk +
|
||||||
|
(uintptr_t)((pageind - (mapelm->bits >>
|
||||||
|
PAGE_SHIFT)) << PAGE_SHIFT));
|
||||||
|
dassert(run->magic == ARENA_RUN_MAGIC);
|
||||||
|
bin = run->bin;
|
||||||
|
#ifdef JEMALLOC_DEBUG
|
||||||
|
{
|
||||||
|
size_t binind = arena_bin_index(arena, bin);
|
||||||
|
arena_bin_info_t *bin_info =
|
||||||
|
&arena_bin_info[binind];
|
||||||
|
assert(((uintptr_t)ptr - ((uintptr_t)run +
|
||||||
|
(uintptr_t)bin_info->reg0_offset)) %
|
||||||
|
bin_info->reg_size == 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
malloc_mutex_lock(&bin->lock);
|
||||||
|
arena_dalloc_bin(arena, chunk, ptr, mapelm);
|
||||||
|
malloc_mutex_unlock(&bin->lock);
|
||||||
|
#ifdef JEMALLOC_TCACHE
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
#ifdef JEMALLOC_TCACHE
|
||||||
|
size_t size = mapelm->bits & ~PAGE_MASK;
|
||||||
|
|
||||||
|
assert(((uintptr_t)ptr & PAGE_MASK) == 0);
|
||||||
|
if (size <= tcache_maxclass) {
|
||||||
|
tcache_t *tcache;
|
||||||
|
|
||||||
|
if ((tcache = tcache_get()) != NULL)
|
||||||
|
tcache_dalloc_large(tcache, ptr, size);
|
||||||
|
else {
|
||||||
|
malloc_mutex_lock(&arena->lock);
|
||||||
|
arena_dalloc_large(arena, chunk, ptr);
|
||||||
|
malloc_mutex_unlock(&arena->lock);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
malloc_mutex_lock(&arena->lock);
|
||||||
|
arena_dalloc_large(arena, chunk, ptr);
|
||||||
|
malloc_mutex_unlock(&arena->lock);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
assert(((uintptr_t)ptr & PAGE_MASK) == 0);
|
||||||
|
malloc_mutex_lock(&arena->lock);
|
||||||
|
arena_dalloc_large(arena, chunk, ptr);
|
||||||
|
malloc_mutex_unlock(&arena->lock);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_INLINES */
|
||||||
|
/******************************************************************************/
|
||||||
169
include/jemalloc/internal/atomic.h
Normal file
169
include/jemalloc/internal/atomic.h
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
/******************************************************************************/
|
||||||
|
#ifdef JEMALLOC_H_TYPES
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_TYPES */
|
||||||
|
/******************************************************************************/
|
||||||
|
#ifdef JEMALLOC_H_STRUCTS
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_STRUCTS */
|
||||||
|
/******************************************************************************/
|
||||||
|
#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)
|
||||||
|
# define atomic_read_z(p) \
|
||||||
|
(size_t)atomic_add_uint64((uint64_t *)p, (uint64_t)0)
|
||||||
|
# define atomic_add_z(p, x) \
|
||||||
|
(size_t)atomic_add_uint64((uint64_t *)p, (uint64_t)x)
|
||||||
|
# define atomic_sub_z(p, x) \
|
||||||
|
(size_t)atomic_sub_uint64((uint64_t *)p, (uint64_t)x)
|
||||||
|
#elif (LG_SIZEOF_PTR == 2)
|
||||||
|
# define atomic_read_z(p) \
|
||||||
|
(size_t)atomic_add_uint32((uint32_t *)p, (uint32_t)0)
|
||||||
|
# define atomic_add_z(p, x) \
|
||||||
|
(size_t)atomic_add_uint32((uint32_t *)p, (uint32_t)x)
|
||||||
|
# define atomic_sub_z(p, x) \
|
||||||
|
(size_t)atomic_sub_uint32((uint32_t *)p, (uint32_t)x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_EXTERNS */
|
||||||
|
/******************************************************************************/
|
||||||
|
#ifdef JEMALLOC_H_INLINES
|
||||||
|
|
||||||
|
#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);
|
||||||
|
uint32_t atomic_add_uint32(uint32_t *p, uint32_t x);
|
||||||
|
uint32_t atomic_sub_uint32(uint32_t *p, uint32_t x);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ATOMIC_C_))
|
||||||
|
/******************************************************************************/
|
||||||
|
/* 64-bit operations. */
|
||||||
|
#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
|
||||||
|
JEMALLOC_INLINE uint64_t
|
||||||
|
atomic_add_uint64(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)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (__sync_sub_and_fetch(p, x));
|
||||||
|
}
|
||||||
|
#elif (defined(JEMALLOC_OSATOMIC))
|
||||||
|
JEMALLOC_INLINE uint64_t
|
||||||
|
atomic_add_uint64(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)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (OSAtomicAdd64(-((int64_t)x), (int64_t *)p));
|
||||||
|
}
|
||||||
|
#elif (defined(__amd64_) || defined(__x86_64__))
|
||||||
|
JEMALLOC_INLINE uint64_t
|
||||||
|
atomic_add_uint64(uint64_t *p, uint64_t x)
|
||||||
|
{
|
||||||
|
|
||||||
|
asm volatile (
|
||||||
|
"lock; xaddq %0, %1;"
|
||||||
|
: "+r" (x), "=m" (*p) /* Outputs. */
|
||||||
|
: "m" (*p) /* Inputs. */
|
||||||
|
);
|
||||||
|
|
||||||
|
return (x);
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE uint64_t
|
||||||
|
atomic_sub_uint64(uint64_t *p, uint64_t x)
|
||||||
|
{
|
||||||
|
|
||||||
|
x = (uint64_t)(-(int64_t)x);
|
||||||
|
asm volatile (
|
||||||
|
"lock; xaddq %0, %1;"
|
||||||
|
: "+r" (x), "=m" (*p) /* Outputs. */
|
||||||
|
: "m" (*p) /* Inputs. */
|
||||||
|
);
|
||||||
|
|
||||||
|
return (x);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# if (LG_SIZEOF_PTR == 3)
|
||||||
|
# error "Missing implementation for 64-bit atomic operations"
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/* 32-bit operations. */
|
||||||
|
#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
|
||||||
|
JEMALLOC_INLINE uint32_t
|
||||||
|
atomic_add_uint32(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)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (__sync_sub_and_fetch(p, x));
|
||||||
|
}
|
||||||
|
#elif (defined(JEMALLOC_OSATOMIC))
|
||||||
|
JEMALLOC_INLINE uint32_t
|
||||||
|
atomic_add_uint32(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)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (OSAtomicAdd32(-((int32_t)x), (int32_t *)p));
|
||||||
|
}
|
||||||
|
#elif (defined(__i386__) || defined(__amd64_) || defined(__x86_64__))
|
||||||
|
JEMALLOC_INLINE uint32_t
|
||||||
|
atomic_add_uint32(uint32_t *p, uint32_t x)
|
||||||
|
{
|
||||||
|
|
||||||
|
asm volatile (
|
||||||
|
"lock; xaddl %0, %1;"
|
||||||
|
: "+r" (x), "=m" (*p) /* Outputs. */
|
||||||
|
: "m" (*p) /* Inputs. */
|
||||||
|
);
|
||||||
|
|
||||||
|
return (x);
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE uint32_t
|
||||||
|
atomic_sub_uint32(uint32_t *p, uint32_t x)
|
||||||
|
{
|
||||||
|
|
||||||
|
x = (uint32_t)(-(int32_t)x);
|
||||||
|
asm volatile (
|
||||||
|
"lock; xaddl %0, %1;"
|
||||||
|
: "+r" (x), "=m" (*p) /* Outputs. */
|
||||||
|
: "m" (*p) /* Inputs. */
|
||||||
|
);
|
||||||
|
|
||||||
|
return (x);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# error "Missing implementation for 32-bit atomic operations"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_INLINES */
|
||||||
|
/******************************************************************************/
|
||||||
184
include/jemalloc/internal/bitmap.h
Normal file
184
include/jemalloc/internal/bitmap.h
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
/******************************************************************************/
|
||||||
|
#ifdef JEMALLOC_H_TYPES
|
||||||
|
|
||||||
|
/* Maximum bitmap bit count is 2^LG_BITMAP_MAXBITS. */
|
||||||
|
#define LG_BITMAP_MAXBITS LG_RUN_MAXREGS
|
||||||
|
|
||||||
|
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 (ZU(1) << LG_BITMAP_GROUP_NBITS)
|
||||||
|
#define BITMAP_GROUP_NBITS_MASK (BITMAP_GROUP_NBITS-1)
|
||||||
|
|
||||||
|
/* Maximum number of levels possible. */
|
||||||
|
#define BITMAP_MAX_LEVELS \
|
||||||
|
(LG_BITMAP_MAXBITS / LG_SIZEOF_BITMAP) \
|
||||||
|
+ !!(LG_BITMAP_MAXBITS % LG_SIZEOF_BITMAP)
|
||||||
|
|
||||||
|
#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;
|
||||||
|
|
||||||
|
/* 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];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_STRUCTS */
|
||||||
|
/******************************************************************************/
|
||||||
|
#ifdef JEMALLOC_H_EXTERNS
|
||||||
|
|
||||||
|
void bitmap_info_init(bitmap_info_t *binfo, size_t nbits);
|
||||||
|
size_t bitmap_info_ngroups(const bitmap_info_t *binfo);
|
||||||
|
size_t bitmap_size(size_t nbits);
|
||||||
|
void bitmap_init(bitmap_t *bitmap, 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)
|
||||||
|
{
|
||||||
|
unsigned 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 & (1LU << (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) == false);
|
||||||
|
goff = bit >> LG_BITMAP_GROUP_NBITS;
|
||||||
|
gp = &bitmap[goff];
|
||||||
|
g = *gp;
|
||||||
|
assert(g & (1LU << (bit & BITMAP_GROUP_NBITS_MASK)));
|
||||||
|
g ^= 1LU << (bit & BITMAP_GROUP_NBITS_MASK);
|
||||||
|
*gp = g;
|
||||||
|
assert(bitmap_get(bitmap, binfo, bit));
|
||||||
|
/* 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 & (1LU << (bit & BITMAP_GROUP_NBITS_MASK)));
|
||||||
|
g ^= 1LU << (bit & BITMAP_GROUP_NBITS_MASK);
|
||||||
|
*gp = g;
|
||||||
|
if (g != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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) == false);
|
||||||
|
|
||||||
|
i = binfo->nlevels - 1;
|
||||||
|
g = bitmap[binfo->levels[i].group_offset];
|
||||||
|
bit = ffsl(g) - 1;
|
||||||
|
while (i > 0) {
|
||||||
|
i--;
|
||||||
|
g = bitmap[binfo->levels[i].group_offset + bit];
|
||||||
|
bit = (bit << LG_BITMAP_GROUP_NBITS) + (ffsl(g) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
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 & (1LU << (bit & BITMAP_GROUP_NBITS_MASK))) == 0);
|
||||||
|
g ^= 1LU << (bit & BITMAP_GROUP_NBITS_MASK);
|
||||||
|
*gp = g;
|
||||||
|
assert(bitmap_get(bitmap, binfo, bit) == false);
|
||||||
|
/* 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 & (1LU << (bit & BITMAP_GROUP_NBITS_MASK)))
|
||||||
|
== 0);
|
||||||
|
g ^= 1LU << (bit & BITMAP_GROUP_NBITS_MASK);
|
||||||
|
*gp = g;
|
||||||
|
if (propagate == false)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_INLINES */
|
||||||
|
/******************************************************************************/
|
||||||
@@ -39,13 +39,17 @@ extern malloc_mutex_t chunks_mtx;
|
|||||||
extern chunk_stats_t stats_chunks;
|
extern chunk_stats_t stats_chunks;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_IVSALLOC
|
||||||
|
extern rtree_t *chunks_rtree;
|
||||||
|
#endif
|
||||||
|
|
||||||
extern size_t chunksize;
|
extern size_t chunksize;
|
||||||
extern size_t chunksize_mask; /* (chunksize - 1). */
|
extern size_t chunksize_mask; /* (chunksize - 1). */
|
||||||
extern size_t chunk_npages;
|
extern size_t chunk_npages;
|
||||||
extern size_t arena_chunk_header_npages;
|
extern size_t map_bias; /* Number of arena chunk header pages. */
|
||||||
extern size_t arena_maxclass; /* Max size class for arenas. */
|
extern size_t arena_maxclass; /* Max size class for arenas. */
|
||||||
|
|
||||||
void *chunk_alloc(size_t size, bool *zero);
|
void *chunk_alloc(size_t size, bool base, bool *zero);
|
||||||
void chunk_dealloc(void *chunk, size_t size);
|
void chunk_dealloc(void *chunk, size_t size);
|
||||||
bool chunk_boot(void);
|
bool chunk_boot(void);
|
||||||
|
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
extern malloc_mutex_t dss_mtx;
|
extern malloc_mutex_t dss_mtx;
|
||||||
|
|
||||||
void *chunk_alloc_dss(size_t size, bool *zero);
|
void *chunk_alloc_dss(size_t size, bool *zero);
|
||||||
|
bool chunk_in_dss(void *chunk);
|
||||||
bool chunk_dealloc_dss(void *chunk, size_t size);
|
bool chunk_dealloc_dss(void *chunk, size_t size);
|
||||||
bool chunk_dss_boot(void);
|
bool chunk_dss_boot(void);
|
||||||
|
|
||||||
@@ -10,8 +10,11 @@
|
|||||||
#ifdef JEMALLOC_H_EXTERNS
|
#ifdef JEMALLOC_H_EXTERNS
|
||||||
|
|
||||||
void *chunk_alloc_mmap(size_t size);
|
void *chunk_alloc_mmap(size_t size);
|
||||||
|
void *chunk_alloc_mmap_noreserve(size_t size);
|
||||||
void chunk_dealloc_mmap(void *chunk, size_t size);
|
void chunk_dealloc_mmap(void *chunk, size_t size);
|
||||||
|
|
||||||
|
bool chunk_mmap_boot(void);
|
||||||
|
|
||||||
#endif /* JEMALLOC_H_EXTERNS */
|
#endif /* JEMALLOC_H_EXTERNS */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
#ifdef JEMALLOC_H_INLINES
|
#ifdef JEMALLOC_H_INLINES
|
||||||
@@ -20,6 +20,7 @@ extern size_t swap_avail;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void *chunk_alloc_swap(size_t size, bool *zero);
|
void *chunk_alloc_swap(size_t size, bool *zero);
|
||||||
|
bool chunk_in_swap(void *chunk);
|
||||||
bool chunk_dealloc_swap(void *chunk, size_t size);
|
bool chunk_dealloc_swap(void *chunk, size_t size);
|
||||||
bool chunk_swap_enable(const int *fds, unsigned nfds, bool prezeroed);
|
bool chunk_swap_enable(const int *fds, unsigned nfds, bool prezeroed);
|
||||||
bool chunk_swap_boot(void);
|
bool chunk_swap_boot(void);
|
||||||
@@ -31,7 +31,7 @@ struct ckhc_s {
|
|||||||
|
|
||||||
struct ckh_s {
|
struct ckh_s {
|
||||||
#ifdef JEMALLOC_DEBUG
|
#ifdef JEMALLOC_DEBUG
|
||||||
#define CKH_MAGIG 0x3af2489d
|
#define CKH_MAGIC 0x3af2489d
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ struct ckh_s {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Used for pseudo-random number generation. */
|
/* Used for pseudo-random number generation. */
|
||||||
#define CKH_A 12345
|
#define CKH_A 1103515241
|
||||||
#define CKH_C 12347
|
#define CKH_C 12347
|
||||||
uint32_t prn_state;
|
uint32_t prn_state;
|
||||||
|
|
||||||
@@ -29,10 +29,18 @@ struct ctl_node_s {
|
|||||||
|
|
||||||
struct ctl_arena_stats_s {
|
struct ctl_arena_stats_s {
|
||||||
bool initialized;
|
bool initialized;
|
||||||
|
unsigned nthreads;
|
||||||
size_t pactive;
|
size_t pactive;
|
||||||
size_t pdirty;
|
size_t pdirty;
|
||||||
#ifdef JEMALLOC_STATS
|
#ifdef JEMALLOC_STATS
|
||||||
arena_stats_t astats;
|
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 elements. */
|
malloc_bin_stats_t *bstats; /* nbins elements. */
|
||||||
malloc_large_stats_t *lstats; /* nlclasses elements. */
|
malloc_large_stats_t *lstats; /* nlclasses elements. */
|
||||||
#endif
|
#endif
|
||||||
@@ -75,17 +83,19 @@ bool ctl_boot(void);
|
|||||||
#define xmallctl(name, oldp, oldlenp, newp, newlen) do { \
|
#define xmallctl(name, oldp, oldlenp, newp, newlen) do { \
|
||||||
if (JEMALLOC_P(mallctl)(name, oldp, oldlenp, newp, newlen) \
|
if (JEMALLOC_P(mallctl)(name, oldp, oldlenp, newp, newlen) \
|
||||||
!= 0) { \
|
!= 0) { \
|
||||||
malloc_write4("<jemalloc>: Invalid xmallctl(\"", name, \
|
malloc_write("<jemalloc>: Failure in xmallctl(\""); \
|
||||||
"\", ...) call\n", ""); \
|
malloc_write(name); \
|
||||||
|
malloc_write("\", ...)\n"); \
|
||||||
abort(); \
|
abort(); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define xmallctlnametomib(name, mibp, miblenp) do { \
|
#define xmallctlnametomib(name, mibp, miblenp) do { \
|
||||||
if (JEMALLOC_P(mallctlnametomib)(name, mibp, miblenp) != 0) { \
|
if (JEMALLOC_P(mallctlnametomib)(name, mibp, miblenp) != 0) { \
|
||||||
malloc_write4( \
|
malloc_write( \
|
||||||
"<jemalloc>: Invalid xmallctlnametomib(\"", name, \
|
"<jemalloc>: Failure in xmallctlnametomib(\""); \
|
||||||
"\", ...) call\n", ""); \
|
malloc_write(name); \
|
||||||
|
malloc_write("\", ...)\n"); \
|
||||||
abort(); \
|
abort(); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
@@ -93,9 +103,8 @@ bool ctl_boot(void);
|
|||||||
#define xmallctlbymib(mib, miblen, oldp, oldlenp, newp, newlen) do { \
|
#define xmallctlbymib(mib, miblen, oldp, oldlenp, newp, newlen) do { \
|
||||||
if (JEMALLOC_P(mallctlbymib)(mib, miblen, oldp, oldlenp, newp, \
|
if (JEMALLOC_P(mallctlbymib)(mib, miblen, oldp, oldlenp, newp, \
|
||||||
newlen) != 0) { \
|
newlen) != 0) { \
|
||||||
malloc_write4( \
|
malloc_write( \
|
||||||
"<jemalloc>: Invalid xmallctlbymib() call\n", "", \
|
"<jemalloc>: Failure in xmallctlbymib()\n"); \
|
||||||
"", ""); \
|
|
||||||
abort(); \
|
abort(); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
@@ -19,7 +19,7 @@ struct extent_node_s {
|
|||||||
|
|
||||||
#ifdef JEMALLOC_PROF
|
#ifdef JEMALLOC_PROF
|
||||||
/* Profile counters, used for huge objects. */
|
/* Profile counters, used for huge objects. */
|
||||||
prof_thr_cnt_t *prof_cnt;
|
prof_ctx_t *prof_ctx;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Pointer to the extent that this tree node is responsible for. */
|
/* Pointer to the extent that this tree node is responsible for. */
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
uint64_t hash(const void *key, size_t len, uint64_t seed);
|
uint64_t hash(const void *key, size_t len, uint64_t seed);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(HASH_C_))
|
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_HASH_C_))
|
||||||
/*
|
/*
|
||||||
* The following hash function is based on MurmurHash64A(), placed into the
|
* The following hash function is based on MurmurHash64A(), placed into the
|
||||||
* public domain by Austin Appleby. See http://murmurhash.googlepages.com/ for
|
* public domain by Austin Appleby. See http://murmurhash.googlepages.com/ for
|
||||||
@@ -26,7 +26,7 @@ uint64_t hash(const void *key, size_t len, uint64_t seed);
|
|||||||
JEMALLOC_INLINE uint64_t
|
JEMALLOC_INLINE uint64_t
|
||||||
hash(const void *key, size_t len, uint64_t seed)
|
hash(const void *key, size_t len, uint64_t seed)
|
||||||
{
|
{
|
||||||
const uint64_t m = 0xc6a4a7935bd1e995;
|
const uint64_t m = 0xc6a4a7935bd1e995LLU;
|
||||||
const int r = 47;
|
const int r = 47;
|
||||||
uint64_t h = seed ^ (len * m);
|
uint64_t h = seed ^ (len * m);
|
||||||
const uint64_t *data = (const uint64_t *)key;
|
const uint64_t *data = (const uint64_t *)key;
|
||||||
@@ -62,7 +62,7 @@ hash(const void *key, size_t len, uint64_t seed)
|
|||||||
h *= m;
|
h *= m;
|
||||||
h ^= h >> r;
|
h ^= h >> r;
|
||||||
|
|
||||||
return h;
|
return (h);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -20,13 +20,16 @@ extern size_t huge_allocated;
|
|||||||
extern malloc_mutex_t huge_mtx;
|
extern malloc_mutex_t huge_mtx;
|
||||||
|
|
||||||
void *huge_malloc(size_t size, bool zero);
|
void *huge_malloc(size_t size, bool zero);
|
||||||
void *huge_palloc(size_t alignment, size_t size);
|
void *huge_palloc(size_t size, size_t alignment, bool zero);
|
||||||
void *huge_ralloc(void *ptr, size_t size, size_t oldsize);
|
void *huge_ralloc_no_move(void *ptr, size_t oldsize, size_t size,
|
||||||
void huge_dalloc(void *ptr);
|
size_t extra);
|
||||||
|
void *huge_ralloc(void *ptr, size_t oldsize, size_t size, size_t extra,
|
||||||
|
size_t alignment, bool zero);
|
||||||
|
void huge_dalloc(void *ptr, bool unmap);
|
||||||
size_t huge_salloc(const void *ptr);
|
size_t huge_salloc(const void *ptr);
|
||||||
#ifdef JEMALLOC_PROF
|
#ifdef JEMALLOC_PROF
|
||||||
prof_thr_cnt_t *huge_prof_cnt_get(const void *ptr);
|
prof_ctx_t *huge_prof_ctx_get(const void *ptr);
|
||||||
void huge_prof_cnt_set(const void *ptr, prof_thr_cnt_t *cnt);
|
void huge_prof_ctx_set(const void *ptr, prof_ctx_t *ctx);
|
||||||
#endif
|
#endif
|
||||||
bool huge_boot(void);
|
bool huge_boot(void);
|
||||||
|
|
||||||
@@ -17,16 +17,35 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#ifndef offsetof
|
||||||
|
# define offsetof(type, member) ((size_t)&(((type *)NULL)->member))
|
||||||
|
#endif
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#define JEMALLOC_MANGLE
|
#define JEMALLOC_MANGLE
|
||||||
#include "../jemalloc@install_suffix@.h"
|
#include "../jemalloc@install_suffix@.h"
|
||||||
|
|
||||||
|
#include "private_namespace.h"
|
||||||
|
|
||||||
|
#if (defined(JEMALLOC_OSATOMIC) || defined(JEMALLOC_OSSPIN))
|
||||||
|
#include <libkern/OSAtomic.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_ZONE
|
||||||
|
#include <mach/mach_error.h>
|
||||||
|
#include <mach/mach_init.h>
|
||||||
|
#include <mach/vm_map.h>
|
||||||
|
#include <malloc/malloc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef JEMALLOC_LAZY_LOCK
|
#ifdef JEMALLOC_LAZY_LOCK
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -36,26 +55,37 @@
|
|||||||
#include "jemalloc/internal/qr.h"
|
#include "jemalloc/internal/qr.h"
|
||||||
#include "jemalloc/internal/ql.h"
|
#include "jemalloc/internal/ql.h"
|
||||||
|
|
||||||
extern void (*JEMALLOC_P(malloc_message))(void *w4opaque, const char *p1,
|
extern void (*JEMALLOC_P(malloc_message))(void *wcbopaque, const char *s);
|
||||||
const char *p2, const char *p3, const char *p4);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Define a custom assert() in order to reduce the chances of deadlock during
|
* Define a custom assert() in order to reduce the chances of deadlock during
|
||||||
* assertion failure.
|
* assertion failure.
|
||||||
*/
|
*/
|
||||||
#ifdef JEMALLOC_DEBUG
|
#ifndef assert
|
||||||
# define assert(e) do { \
|
# ifdef JEMALLOC_DEBUG
|
||||||
|
# define assert(e) do { \
|
||||||
if (!(e)) { \
|
if (!(e)) { \
|
||||||
char line_buf[UMAX2S_BUFSIZE]; \
|
char line_buf[UMAX2S_BUFSIZE]; \
|
||||||
malloc_write4("<jemalloc>: ", __FILE__, ":", \
|
malloc_write("<jemalloc>: "); \
|
||||||
umax2s(__LINE__, 10, line_buf)); \
|
malloc_write(__FILE__); \
|
||||||
malloc_write4(": Failed assertion: ", "\"", #e, \
|
malloc_write(":"); \
|
||||||
"\"\n"); \
|
malloc_write(u2s(__LINE__, 10, line_buf)); \
|
||||||
|
malloc_write(": Failed assertion: "); \
|
||||||
|
malloc_write("\""); \
|
||||||
|
malloc_write(#e); \
|
||||||
|
malloc_write("\"\n"); \
|
||||||
abort(); \
|
abort(); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
# else
|
||||||
|
# define assert(e)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_DEBUG
|
||||||
|
# define dassert(e) assert(e)
|
||||||
#else
|
#else
|
||||||
#define assert(e)
|
# define dassert(e)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -74,6 +104,8 @@ extern void (*JEMALLOC_P(malloc_message))(void *w4opaque, const char *p1,
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
#define JEMALLOC_H_TYPES
|
#define JEMALLOC_H_TYPES
|
||||||
|
|
||||||
|
#define ALLOCM_LG_ALIGN_MASK ((int)0x3f)
|
||||||
|
|
||||||
#define ZU(z) ((size_t)z)
|
#define ZU(z) ((size_t)z)
|
||||||
|
|
||||||
#ifndef __DECONST
|
#ifndef __DECONST
|
||||||
@@ -89,8 +121,8 @@ extern void (*JEMALLOC_P(malloc_message))(void *w4opaque, const char *p1,
|
|||||||
# define JEMALLOC_INLINE static inline
|
# define JEMALLOC_INLINE static inline
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Size of stack-allocated buffer passed to strerror_r(). */
|
/* Size of stack-allocated buffer passed to buferror(). */
|
||||||
#define STRERROR_BUF 64
|
#define BUFERROR_BUF 64
|
||||||
|
|
||||||
/* Minimum alignment of allocations is 2^LG_QUANTUM bytes. */
|
/* Minimum alignment of allocations is 2^LG_QUANTUM bytes. */
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
@@ -128,12 +160,19 @@ extern void (*JEMALLOC_P(malloc_message))(void *w4opaque, const char *p1,
|
|||||||
#define QUANTUM_CEILING(a) \
|
#define QUANTUM_CEILING(a) \
|
||||||
(((a) + QUANTUM_MASK) & ~QUANTUM_MASK)
|
(((a) + QUANTUM_MASK) & ~QUANTUM_MASK)
|
||||||
|
|
||||||
#define SIZEOF_PTR (1U << LG_SIZEOF_PTR)
|
#define LONG ((size_t)(1U << LG_SIZEOF_LONG))
|
||||||
|
#define LONG_MASK (LONG - 1)
|
||||||
|
|
||||||
/* We can't use TLS in non-PIC programs, since TLS relies on loader magic. */
|
/* Return the smallest long multiple that is >= a. */
|
||||||
#if (!defined(PIC) && !defined(NO_TLS))
|
#define LONG_CEILING(a) \
|
||||||
# define NO_TLS
|
(((a) + LONG_MASK) & ~LONG_MASK)
|
||||||
#endif
|
|
||||||
|
#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.
|
* Maximum size of L1 cache line. This is used to avoid cache line aliasing.
|
||||||
@@ -156,6 +195,16 @@ extern void (*JEMALLOC_P(malloc_message))(void *w4opaque, const char *p1,
|
|||||||
#define STATIC_PAGE_SIZE ((size_t)(1U << STATIC_PAGE_SHIFT))
|
#define STATIC_PAGE_SIZE ((size_t)(1U << STATIC_PAGE_SHIFT))
|
||||||
#define STATIC_PAGE_MASK ((size_t)(STATIC_PAGE_SIZE - 1))
|
#define STATIC_PAGE_MASK ((size_t)(STATIC_PAGE_SIZE - 1))
|
||||||
|
|
||||||
|
#ifdef PAGE_SHIFT
|
||||||
|
# undef PAGE_SHIFT
|
||||||
|
#endif
|
||||||
|
#ifdef PAGE_SIZE
|
||||||
|
# undef PAGE_SIZE
|
||||||
|
#endif
|
||||||
|
#ifdef PAGE_MASK
|
||||||
|
# undef PAGE_MASK
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DYNAMIC_PAGE_SHIFT
|
#ifdef DYNAMIC_PAGE_SHIFT
|
||||||
# define PAGE_SHIFT lg_pagesize
|
# define PAGE_SHIFT lg_pagesize
|
||||||
# define PAGE_SIZE pagesize
|
# define PAGE_SIZE pagesize
|
||||||
@@ -170,6 +219,7 @@ extern void (*JEMALLOC_P(malloc_message))(void *w4opaque, const char *p1,
|
|||||||
#define PAGE_CEILING(s) \
|
#define PAGE_CEILING(s) \
|
||||||
(((s) + PAGE_MASK) & ~PAGE_MASK)
|
(((s) + PAGE_MASK) & ~PAGE_MASK)
|
||||||
|
|
||||||
|
#include "jemalloc/internal/atomic.h"
|
||||||
#include "jemalloc/internal/prn.h"
|
#include "jemalloc/internal/prn.h"
|
||||||
#include "jemalloc/internal/ckh.h"
|
#include "jemalloc/internal/ckh.h"
|
||||||
#include "jemalloc/internal/stats.h"
|
#include "jemalloc/internal/stats.h"
|
||||||
@@ -178,32 +228,50 @@ extern void (*JEMALLOC_P(malloc_message))(void *w4opaque, const char *p1,
|
|||||||
#include "jemalloc/internal/mb.h"
|
#include "jemalloc/internal/mb.h"
|
||||||
#include "jemalloc/internal/extent.h"
|
#include "jemalloc/internal/extent.h"
|
||||||
#include "jemalloc/internal/arena.h"
|
#include "jemalloc/internal/arena.h"
|
||||||
|
#include "jemalloc/internal/bitmap.h"
|
||||||
#include "jemalloc/internal/base.h"
|
#include "jemalloc/internal/base.h"
|
||||||
#include "jemalloc/internal/chunk.h"
|
#include "jemalloc/internal/chunk.h"
|
||||||
#include "jemalloc/internal/huge.h"
|
#include "jemalloc/internal/huge.h"
|
||||||
|
#include "jemalloc/internal/rtree.h"
|
||||||
#include "jemalloc/internal/tcache.h"
|
#include "jemalloc/internal/tcache.h"
|
||||||
#include "jemalloc/internal/hash.h"
|
#include "jemalloc/internal/hash.h"
|
||||||
|
#ifdef JEMALLOC_ZONE
|
||||||
|
#include "jemalloc/internal/zone.h"
|
||||||
|
#endif
|
||||||
#include "jemalloc/internal/prof.h"
|
#include "jemalloc/internal/prof.h"
|
||||||
|
|
||||||
#undef JEMALLOC_H_TYPES
|
#undef JEMALLOC_H_TYPES
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
#define JEMALLOC_H_STRUCTS
|
#define JEMALLOC_H_STRUCTS
|
||||||
|
|
||||||
|
#include "jemalloc/internal/atomic.h"
|
||||||
#include "jemalloc/internal/prn.h"
|
#include "jemalloc/internal/prn.h"
|
||||||
#include "jemalloc/internal/ckh.h"
|
#include "jemalloc/internal/ckh.h"
|
||||||
#include "jemalloc/internal/stats.h"
|
#include "jemalloc/internal/stats.h"
|
||||||
#include "jemalloc/internal/ctl.h"
|
#include "jemalloc/internal/ctl.h"
|
||||||
#include "jemalloc/internal/mutex.h"
|
#include "jemalloc/internal/mutex.h"
|
||||||
#include "jemalloc/internal/mb.h"
|
#include "jemalloc/internal/mb.h"
|
||||||
|
#include "jemalloc/internal/bitmap.h"
|
||||||
#include "jemalloc/internal/extent.h"
|
#include "jemalloc/internal/extent.h"
|
||||||
#include "jemalloc/internal/arena.h"
|
#include "jemalloc/internal/arena.h"
|
||||||
#include "jemalloc/internal/base.h"
|
#include "jemalloc/internal/base.h"
|
||||||
#include "jemalloc/internal/chunk.h"
|
#include "jemalloc/internal/chunk.h"
|
||||||
#include "jemalloc/internal/huge.h"
|
#include "jemalloc/internal/huge.h"
|
||||||
|
#include "jemalloc/internal/rtree.h"
|
||||||
#include "jemalloc/internal/tcache.h"
|
#include "jemalloc/internal/tcache.h"
|
||||||
#include "jemalloc/internal/hash.h"
|
#include "jemalloc/internal/hash.h"
|
||||||
|
#ifdef JEMALLOC_ZONE
|
||||||
|
#include "jemalloc/internal/zone.h"
|
||||||
|
#endif
|
||||||
#include "jemalloc/internal/prof.h"
|
#include "jemalloc/internal/prof.h"
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
typedef struct {
|
||||||
|
uint64_t allocated;
|
||||||
|
uint64_t deallocated;
|
||||||
|
} thread_allocated_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
#undef JEMALLOC_H_STRUCTS
|
#undef JEMALLOC_H_STRUCTS
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
#define JEMALLOC_H_EXTERNS
|
#define JEMALLOC_H_EXTERNS
|
||||||
@@ -221,6 +289,7 @@ extern bool opt_xmalloc;
|
|||||||
#ifdef JEMALLOC_FILL
|
#ifdef JEMALLOC_FILL
|
||||||
extern bool opt_zero;
|
extern bool opt_zero;
|
||||||
#endif
|
#endif
|
||||||
|
extern size_t opt_narenas;
|
||||||
|
|
||||||
#ifdef DYNAMIC_PAGE_SHIFT
|
#ifdef DYNAMIC_PAGE_SHIFT
|
||||||
extern size_t pagesize;
|
extern size_t pagesize;
|
||||||
@@ -232,13 +301,25 @@ extern size_t lg_pagesize;
|
|||||||
extern unsigned ncpus;
|
extern unsigned ncpus;
|
||||||
|
|
||||||
extern malloc_mutex_t arenas_lock; /* Protects arenas initialization. */
|
extern malloc_mutex_t arenas_lock; /* Protects arenas initialization. */
|
||||||
|
extern pthread_key_t arenas_tsd;
|
||||||
#ifndef NO_TLS
|
#ifndef NO_TLS
|
||||||
/*
|
/*
|
||||||
* Map of pthread_self() --> arenas[???], used for selecting an arena to use
|
* Map of pthread_self() --> arenas[???], used for selecting an arena to use
|
||||||
* for allocations.
|
* for allocations.
|
||||||
*/
|
*/
|
||||||
extern __thread arena_t *arenas_map JEMALLOC_ATTR(tls_model("initial-exec"));
|
extern __thread arena_t *arenas_tls JEMALLOC_ATTR(tls_model("initial-exec"));
|
||||||
|
# define ARENA_GET() arenas_tls
|
||||||
|
# define ARENA_SET(v) do { \
|
||||||
|
arenas_tls = (v); \
|
||||||
|
pthread_setspecific(arenas_tsd, (void *)(v)); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
# define ARENA_GET() ((arena_t *)pthread_getspecific(arenas_tsd))
|
||||||
|
# define ARENA_SET(v) do { \
|
||||||
|
pthread_setspecific(arenas_tsd, (void *)(v)); \
|
||||||
|
} while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Arenas that are used to service external requests. Not all elements of the
|
* Arenas that are used to service external requests. Not all elements of the
|
||||||
* arenas array are necessarily used; arenas are created lazily as needed.
|
* arenas array are necessarily used; arenas are created lazily as needed.
|
||||||
@@ -246,30 +327,65 @@ extern __thread arena_t *arenas_map JEMALLOC_ATTR(tls_model("initial-exec"));
|
|||||||
extern arena_t **arenas;
|
extern arena_t **arenas;
|
||||||
extern unsigned narenas;
|
extern unsigned narenas;
|
||||||
|
|
||||||
arena_t *arenas_extend(unsigned ind);
|
#ifdef JEMALLOC_STATS
|
||||||
#ifndef NO_TLS
|
# ifndef NO_TLS
|
||||||
arena_t *choose_arena_hard(void);
|
extern __thread thread_allocated_t thread_allocated_tls;
|
||||||
|
# define ALLOCATED_GET() (thread_allocated_tls.allocated)
|
||||||
|
# define ALLOCATEDP_GET() (&thread_allocated_tls.allocated)
|
||||||
|
# define DEALLOCATED_GET() (thread_allocated_tls.deallocated)
|
||||||
|
# define DEALLOCATEDP_GET() (&thread_allocated_tls.deallocated)
|
||||||
|
# define ALLOCATED_ADD(a, d) do { \
|
||||||
|
thread_allocated_tls.allocated += a; \
|
||||||
|
thread_allocated_tls.deallocated += d; \
|
||||||
|
} while (0)
|
||||||
|
# else
|
||||||
|
extern pthread_key_t thread_allocated_tsd;
|
||||||
|
thread_allocated_t *thread_allocated_get_hard(void);
|
||||||
|
|
||||||
|
# define ALLOCATED_GET() (thread_allocated_get()->allocated)
|
||||||
|
# define ALLOCATEDP_GET() (&thread_allocated_get()->allocated)
|
||||||
|
# define DEALLOCATED_GET() (thread_allocated_get()->deallocated)
|
||||||
|
# define DEALLOCATEDP_GET() (&thread_allocated_get()->deallocated)
|
||||||
|
# define ALLOCATED_ADD(a, d) do { \
|
||||||
|
thread_allocated_t *thread_allocated = thread_allocated_get(); \
|
||||||
|
thread_allocated->allocated += (a); \
|
||||||
|
thread_allocated->deallocated += (d); \
|
||||||
|
} while (0)
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
arena_t *arenas_extend(unsigned ind);
|
||||||
|
arena_t *choose_arena_hard(void);
|
||||||
|
int buferror(int errnum, char *buf, size_t buflen);
|
||||||
|
void jemalloc_prefork(void);
|
||||||
|
void jemalloc_postfork(void);
|
||||||
|
|
||||||
|
#include "jemalloc/internal/atomic.h"
|
||||||
#include "jemalloc/internal/prn.h"
|
#include "jemalloc/internal/prn.h"
|
||||||
#include "jemalloc/internal/ckh.h"
|
#include "jemalloc/internal/ckh.h"
|
||||||
#include "jemalloc/internal/stats.h"
|
#include "jemalloc/internal/stats.h"
|
||||||
#include "jemalloc/internal/ctl.h"
|
#include "jemalloc/internal/ctl.h"
|
||||||
#include "jemalloc/internal/mutex.h"
|
#include "jemalloc/internal/mutex.h"
|
||||||
#include "jemalloc/internal/mb.h"
|
#include "jemalloc/internal/mb.h"
|
||||||
|
#include "jemalloc/internal/bitmap.h"
|
||||||
#include "jemalloc/internal/extent.h"
|
#include "jemalloc/internal/extent.h"
|
||||||
#include "jemalloc/internal/arena.h"
|
#include "jemalloc/internal/arena.h"
|
||||||
#include "jemalloc/internal/base.h"
|
#include "jemalloc/internal/base.h"
|
||||||
#include "jemalloc/internal/chunk.h"
|
#include "jemalloc/internal/chunk.h"
|
||||||
#include "jemalloc/internal/huge.h"
|
#include "jemalloc/internal/huge.h"
|
||||||
|
#include "jemalloc/internal/rtree.h"
|
||||||
#include "jemalloc/internal/tcache.h"
|
#include "jemalloc/internal/tcache.h"
|
||||||
#include "jemalloc/internal/hash.h"
|
#include "jemalloc/internal/hash.h"
|
||||||
|
#ifdef JEMALLOC_ZONE
|
||||||
|
#include "jemalloc/internal/zone.h"
|
||||||
|
#endif
|
||||||
#include "jemalloc/internal/prof.h"
|
#include "jemalloc/internal/prof.h"
|
||||||
|
|
||||||
#undef JEMALLOC_H_EXTERNS
|
#undef JEMALLOC_H_EXTERNS
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
#define JEMALLOC_H_INLINES
|
#define JEMALLOC_H_INLINES
|
||||||
|
|
||||||
|
#include "jemalloc/internal/atomic.h"
|
||||||
#include "jemalloc/internal/prn.h"
|
#include "jemalloc/internal/prn.h"
|
||||||
#include "jemalloc/internal/ckh.h"
|
#include "jemalloc/internal/ckh.h"
|
||||||
#include "jemalloc/internal/stats.h"
|
#include "jemalloc/internal/stats.h"
|
||||||
@@ -282,21 +398,153 @@ arena_t *choose_arena_hard(void);
|
|||||||
#include "jemalloc/internal/huge.h"
|
#include "jemalloc/internal/huge.h"
|
||||||
|
|
||||||
#ifndef JEMALLOC_ENABLE_INLINE
|
#ifndef JEMALLOC_ENABLE_INLINE
|
||||||
void malloc_write4(const char *p1, const char *p2, const char *p3,
|
size_t pow2_ceil(size_t x);
|
||||||
const char *p4);
|
size_t s2u(size_t size);
|
||||||
|
size_t sa2u(size_t size, size_t alignment, size_t *run_size_p);
|
||||||
|
void malloc_write(const char *s);
|
||||||
arena_t *choose_arena(void);
|
arena_t *choose_arena(void);
|
||||||
|
# if (defined(JEMALLOC_STATS) && defined(NO_TLS))
|
||||||
|
thread_allocated_t *thread_allocated_get(void);
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_))
|
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_))
|
||||||
|
/* Compute the smallest power of 2 that is >= x. */
|
||||||
|
JEMALLOC_INLINE size_t
|
||||||
|
pow2_ceil(size_t x)
|
||||||
|
{
|
||||||
|
|
||||||
|
x--;
|
||||||
|
x |= x >> 1;
|
||||||
|
x |= x >> 2;
|
||||||
|
x |= x >> 4;
|
||||||
|
x |= x >> 8;
|
||||||
|
x |= x >> 16;
|
||||||
|
#if (LG_SIZEOF_PTR == 3)
|
||||||
|
x |= x >> 32;
|
||||||
|
#endif
|
||||||
|
x++;
|
||||||
|
return (x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute usable size that would result from allocating an object with the
|
||||||
|
* specified size.
|
||||||
|
*/
|
||||||
|
JEMALLOC_INLINE size_t
|
||||||
|
s2u(size_t size)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (size <= small_maxclass)
|
||||||
|
return (arena_bin_info[SMALL_SIZE2BIN(size)].reg_size);
|
||||||
|
if (size <= arena_maxclass)
|
||||||
|
return (PAGE_CEILING(size));
|
||||||
|
return (CHUNK_CEILING(size));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute usable size that would result from allocating an object with the
|
||||||
|
* specified size and alignment.
|
||||||
|
*/
|
||||||
|
JEMALLOC_INLINE size_t
|
||||||
|
sa2u(size_t size, size_t alignment, size_t *run_size_p)
|
||||||
|
{
|
||||||
|
size_t usize;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* Depending on runtime settings, it is possible that arena_malloc()
|
||||||
|
* will further round up to a power of two, but that never causes
|
||||||
|
* correctness issues.
|
||||||
|
*/
|
||||||
|
usize = (size + (alignment - 1)) & (-alignment);
|
||||||
|
/*
|
||||||
|
* (usize < size) protects against the combination of maximal
|
||||||
|
* alignment and size greater than maximal alignment.
|
||||||
|
*/
|
||||||
|
if (usize < size) {
|
||||||
|
/* size_t overflow. */
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (usize <= arena_maxclass && alignment <= PAGE_SIZE) {
|
||||||
|
if (usize <= small_maxclass)
|
||||||
|
return (arena_bin_info[SMALL_SIZE2BIN(usize)].reg_size);
|
||||||
|
return (PAGE_CEILING(usize));
|
||||||
|
} else {
|
||||||
|
size_t run_size;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We can't achieve subpage alignment, so round up alignment
|
||||||
|
* permanently; it makes later calculations simpler.
|
||||||
|
*/
|
||||||
|
alignment = PAGE_CEILING(alignment);
|
||||||
|
usize = PAGE_CEILING(size);
|
||||||
|
/*
|
||||||
|
* (usize < size) protects against very large sizes within
|
||||||
|
* PAGE_SIZE of SIZE_T_MAX.
|
||||||
|
*
|
||||||
|
* (usize + alignment < usize) protects against the
|
||||||
|
* combination of maximal alignment and usize large enough
|
||||||
|
* to cause overflow. This is similar to the first overflow
|
||||||
|
* check above, but it needs to be repeated due to the new
|
||||||
|
* usize value, which may now be *equal* to maximal
|
||||||
|
* alignment, whereas before we only detected overflow if the
|
||||||
|
* original size was *greater* than maximal alignment.
|
||||||
|
*/
|
||||||
|
if (usize < size || usize + alignment < usize) {
|
||||||
|
/* size_t overflow. */
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the size of the over-size run that arena_palloc()
|
||||||
|
* would need to allocate in order to guarantee the alignment.
|
||||||
|
*/
|
||||||
|
if (usize >= alignment)
|
||||||
|
run_size = usize + alignment - PAGE_SIZE;
|
||||||
|
else {
|
||||||
|
/*
|
||||||
|
* It is possible that (alignment << 1) will cause
|
||||||
|
* overflow, but it doesn't matter because we also
|
||||||
|
* subtract PAGE_SIZE, which in the case of overflow
|
||||||
|
* leaves us with a very large run_size. That causes
|
||||||
|
* the first conditional below to fail, which means
|
||||||
|
* that the bogus run_size value never gets used for
|
||||||
|
* anything important.
|
||||||
|
*/
|
||||||
|
run_size = (alignment << 1) - PAGE_SIZE;
|
||||||
|
}
|
||||||
|
if (run_size_p != NULL)
|
||||||
|
*run_size_p = run_size;
|
||||||
|
|
||||||
|
if (run_size <= arena_maxclass)
|
||||||
|
return (PAGE_CEILING(usize));
|
||||||
|
return (CHUNK_CEILING(usize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wrapper around malloc_message() that avoids the need for
|
* Wrapper around malloc_message() that avoids the need for
|
||||||
* JEMALLOC_P(malloc_message)(...) throughout the code.
|
* JEMALLOC_P(malloc_message)(...) throughout the code.
|
||||||
*/
|
*/
|
||||||
JEMALLOC_INLINE void
|
JEMALLOC_INLINE void
|
||||||
malloc_write4(const char *p1, const char *p2, const char *p3, const char *p4)
|
malloc_write(const char *s)
|
||||||
{
|
{
|
||||||
|
|
||||||
JEMALLOC_P(malloc_message)(NULL, p1, p2, p3, p4);
|
JEMALLOC_P(malloc_message)(NULL, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -308,78 +556,49 @@ choose_arena(void)
|
|||||||
{
|
{
|
||||||
arena_t *ret;
|
arena_t *ret;
|
||||||
|
|
||||||
/*
|
ret = ARENA_GET();
|
||||||
* We can only use TLS if this is a PIC library, since for the static
|
|
||||||
* library version, libc's malloc is used by TLS allocation, which
|
|
||||||
* introduces a bootstrapping issue.
|
|
||||||
*/
|
|
||||||
#ifndef NO_TLS
|
|
||||||
ret = arenas_map;
|
|
||||||
if (ret == NULL) {
|
if (ret == NULL) {
|
||||||
ret = choose_arena_hard();
|
ret = choose_arena_hard();
|
||||||
assert(ret != NULL);
|
assert(ret != NULL);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
if (isthreaded && narenas > 1) {
|
|
||||||
unsigned long ind;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Hash pthread_self() to one of the arenas. There is a prime
|
|
||||||
* number of arenas, so this has a reasonable chance of
|
|
||||||
* working. Even so, the hashing can be easily thwarted by
|
|
||||||
* inconvenient pthread_self() values. Without specific
|
|
||||||
* knowledge of how pthread_self() calculates values, we can't
|
|
||||||
* easily do much better than this.
|
|
||||||
*/
|
|
||||||
ind = (unsigned long) pthread_self() % narenas;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Optimistially assume that arenas[ind] has been initialized.
|
|
||||||
* At worst, we find out that some other thread has already
|
|
||||||
* done so, after acquiring the lock in preparation. Note that
|
|
||||||
* this lazy locking also has the effect of lazily forcing
|
|
||||||
* cache coherency; without the lock acquisition, there's no
|
|
||||||
* guarantee that modification of arenas[ind] by another thread
|
|
||||||
* would be seen on this CPU for an arbitrary amount of time.
|
|
||||||
*
|
|
||||||
* In general, this approach to modifying a synchronized value
|
|
||||||
* isn't a good idea, but in this case we only ever modify the
|
|
||||||
* value once, so things work out well.
|
|
||||||
*/
|
|
||||||
ret = arenas[ind];
|
|
||||||
if (ret == NULL) {
|
|
||||||
/*
|
|
||||||
* Avoid races with another thread that may have already
|
|
||||||
* initialized arenas[ind].
|
|
||||||
*/
|
|
||||||
malloc_mutex_lock(&arenas_lock);
|
|
||||||
if (arenas[ind] == NULL)
|
|
||||||
ret = arenas_extend((unsigned)ind);
|
|
||||||
else
|
|
||||||
ret = arenas[ind];
|
|
||||||
malloc_mutex_unlock(&arenas_lock);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
ret = arenas[0];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
assert(ret != NULL);
|
|
||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (defined(JEMALLOC_STATS) && defined(NO_TLS))
|
||||||
|
JEMALLOC_INLINE thread_allocated_t *
|
||||||
|
thread_allocated_get(void)
|
||||||
|
{
|
||||||
|
thread_allocated_t *thread_allocated = (thread_allocated_t *)
|
||||||
|
pthread_getspecific(thread_allocated_tsd);
|
||||||
|
|
||||||
|
if (thread_allocated == NULL)
|
||||||
|
return (thread_allocated_get_hard());
|
||||||
|
return (thread_allocated);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "jemalloc/internal/bitmap.h"
|
||||||
|
#include "jemalloc/internal/rtree.h"
|
||||||
#include "jemalloc/internal/tcache.h"
|
#include "jemalloc/internal/tcache.h"
|
||||||
#include "jemalloc/internal/arena.h"
|
#include "jemalloc/internal/arena.h"
|
||||||
#include "jemalloc/internal/hash.h"
|
#include "jemalloc/internal/hash.h"
|
||||||
#include "jemalloc/internal/prof.h"
|
#ifdef JEMALLOC_ZONE
|
||||||
|
#include "jemalloc/internal/zone.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef JEMALLOC_ENABLE_INLINE
|
#ifndef JEMALLOC_ENABLE_INLINE
|
||||||
void *imalloc(size_t size);
|
void *imalloc(size_t size);
|
||||||
void *icalloc(size_t size);
|
void *icalloc(size_t size);
|
||||||
void *ipalloc(size_t alignment, size_t size);
|
void *ipalloc(size_t usize, size_t alignment, bool zero);
|
||||||
size_t isalloc(const void *ptr);
|
size_t isalloc(const void *ptr);
|
||||||
void *iralloc(void *ptr, size_t size);
|
# ifdef JEMALLOC_IVSALLOC
|
||||||
|
size_t ivsalloc(const void *ptr);
|
||||||
|
# endif
|
||||||
void idalloc(void *ptr);
|
void idalloc(void *ptr);
|
||||||
|
void *iralloc(void *ptr, size_t size, size_t extra, size_t alignment,
|
||||||
|
bool zero, bool no_move);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_))
|
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_))
|
||||||
@@ -406,94 +625,38 @@ icalloc(size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_INLINE void *
|
JEMALLOC_INLINE void *
|
||||||
ipalloc(size_t alignment, size_t size)
|
ipalloc(size_t usize, size_t alignment, bool zero)
|
||||||
{
|
{
|
||||||
void *ret;
|
void *ret;
|
||||||
size_t ceil_size;
|
|
||||||
|
|
||||||
/*
|
assert(usize != 0);
|
||||||
* Round size up to the nearest multiple of alignment.
|
assert(usize == sa2u(usize, alignment, NULL));
|
||||||
*
|
|
||||||
* 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
|
|
||||||
*
|
|
||||||
* Depending on runtime settings, it is possible that arena_malloc()
|
|
||||||
* will further round up to a power of two, but that never causes
|
|
||||||
* correctness issues.
|
|
||||||
*/
|
|
||||||
ceil_size = (size + (alignment - 1)) & (-alignment);
|
|
||||||
/*
|
|
||||||
* (ceil_size < size) protects against the combination of maximal
|
|
||||||
* alignment and size greater than maximal alignment.
|
|
||||||
*/
|
|
||||||
if (ceil_size < size) {
|
|
||||||
/* size_t overflow. */
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ceil_size <= PAGE_SIZE || (alignment <= PAGE_SIZE
|
if (usize <= arena_maxclass && alignment <= PAGE_SIZE)
|
||||||
&& ceil_size <= arena_maxclass))
|
ret = arena_malloc(usize, zero);
|
||||||
ret = arena_malloc(ceil_size, false);
|
|
||||||
else {
|
else {
|
||||||
size_t run_size;
|
size_t run_size
|
||||||
|
#ifdef JEMALLOC_CC_SILENCE
|
||||||
|
= 0
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can't achieve subpage alignment, so round up alignment
|
* Ideally we would only ever call sa2u() once per aligned
|
||||||
* permanently; it makes later calculations simpler.
|
* allocation request, and the caller of this function has
|
||||||
|
* already done so once. However, it's rather burdensome to
|
||||||
|
* require every caller to pass in run_size, especially given
|
||||||
|
* that it's only relevant to large allocations. Therefore,
|
||||||
|
* just call it again here in order to get run_size.
|
||||||
*/
|
*/
|
||||||
alignment = PAGE_CEILING(alignment);
|
sa2u(usize, alignment, &run_size);
|
||||||
ceil_size = PAGE_CEILING(size);
|
|
||||||
/*
|
|
||||||
* (ceil_size < size) protects against very large sizes within
|
|
||||||
* PAGE_SIZE of SIZE_T_MAX.
|
|
||||||
*
|
|
||||||
* (ceil_size + alignment < ceil_size) protects against the
|
|
||||||
* combination of maximal alignment and ceil_size large enough
|
|
||||||
* to cause overflow. This is similar to the first overflow
|
|
||||||
* check above, but it needs to be repeated due to the new
|
|
||||||
* ceil_size value, which may now be *equal* to maximal
|
|
||||||
* alignment, whereas before we only detected overflow if the
|
|
||||||
* original size was *greater* than maximal alignment.
|
|
||||||
*/
|
|
||||||
if (ceil_size < size || ceil_size + alignment < ceil_size) {
|
|
||||||
/* size_t overflow. */
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Calculate the size of the over-size run that arena_palloc()
|
|
||||||
* would need to allocate in order to guarantee the alignment.
|
|
||||||
*/
|
|
||||||
if (ceil_size >= alignment)
|
|
||||||
run_size = ceil_size + alignment - PAGE_SIZE;
|
|
||||||
else {
|
|
||||||
/*
|
|
||||||
* It is possible that (alignment << 1) will cause
|
|
||||||
* overflow, but it doesn't matter because we also
|
|
||||||
* subtract PAGE_SIZE, which in the case of overflow
|
|
||||||
* leaves us with a very large run_size. That causes
|
|
||||||
* the first conditional below to fail, which means
|
|
||||||
* that the bogus run_size value never gets used for
|
|
||||||
* anything important.
|
|
||||||
*/
|
|
||||||
run_size = (alignment << 1) - PAGE_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (run_size <= arena_maxclass) {
|
if (run_size <= arena_maxclass) {
|
||||||
ret = arena_palloc(choose_arena(), alignment, ceil_size,
|
ret = arena_palloc(choose_arena(), usize, run_size,
|
||||||
run_size);
|
alignment, zero);
|
||||||
} else if (alignment <= chunksize)
|
} else if (alignment <= chunksize)
|
||||||
ret = huge_malloc(ceil_size, false);
|
ret = huge_malloc(usize, zero);
|
||||||
else
|
else
|
||||||
ret = huge_palloc(alignment, ceil_size);
|
ret = huge_palloc(usize, alignment, zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(((uintptr_t)ret & (alignment - 1)) == 0);
|
assert(((uintptr_t)ret & (alignment - 1)) == 0);
|
||||||
@@ -511,30 +674,31 @@ isalloc(const void *ptr)
|
|||||||
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
||||||
if (chunk != ptr) {
|
if (chunk != ptr) {
|
||||||
/* Region. */
|
/* Region. */
|
||||||
assert(chunk->arena->magic == ARENA_MAGIC);
|
dassert(chunk->arena->magic == ARENA_MAGIC);
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_PROF
|
||||||
|
ret = arena_salloc_demote(ptr);
|
||||||
|
#else
|
||||||
ret = arena_salloc(ptr);
|
ret = arena_salloc(ptr);
|
||||||
|
#endif
|
||||||
} else
|
} else
|
||||||
ret = huge_salloc(ptr);
|
ret = huge_salloc(ptr);
|
||||||
|
|
||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_INLINE void *
|
#ifdef JEMALLOC_IVSALLOC
|
||||||
iralloc(void *ptr, size_t size)
|
JEMALLOC_INLINE size_t
|
||||||
|
ivsalloc(const void *ptr)
|
||||||
{
|
{
|
||||||
size_t oldsize;
|
|
||||||
|
|
||||||
assert(ptr != NULL);
|
/* Return 0 if ptr is not within a chunk managed by jemalloc. */
|
||||||
assert(size != 0);
|
if (rtree_get(chunks_rtree, (uintptr_t)CHUNK_ADDR2BASE(ptr)) == NULL)
|
||||||
|
return (0);
|
||||||
|
|
||||||
oldsize = isalloc(ptr);
|
return (isalloc(ptr));
|
||||||
|
|
||||||
if (size <= arena_maxclass)
|
|
||||||
return (arena_ralloc(ptr, size, oldsize));
|
|
||||||
else
|
|
||||||
return (huge_ralloc(ptr, size, oldsize));
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
JEMALLOC_INLINE void
|
JEMALLOC_INLINE void
|
||||||
idalloc(void *ptr)
|
idalloc(void *ptr)
|
||||||
@@ -547,9 +711,78 @@ idalloc(void *ptr)
|
|||||||
if (chunk != ptr)
|
if (chunk != ptr)
|
||||||
arena_dalloc(chunk->arena, chunk, ptr);
|
arena_dalloc(chunk->arena, chunk, ptr);
|
||||||
else
|
else
|
||||||
huge_dalloc(ptr);
|
huge_dalloc(ptr, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE void *
|
||||||
|
iralloc(void *ptr, size_t size, size_t extra, size_t alignment, bool zero,
|
||||||
|
bool no_move)
|
||||||
|
{
|
||||||
|
void *ret;
|
||||||
|
size_t oldsize;
|
||||||
|
|
||||||
|
assert(ptr != NULL);
|
||||||
|
assert(size != 0);
|
||||||
|
|
||||||
|
oldsize = isalloc(ptr);
|
||||||
|
|
||||||
|
if (alignment != 0 && ((uintptr_t)ptr & ((uintptr_t)alignment-1))
|
||||||
|
!= 0) {
|
||||||
|
size_t usize, copysize;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Existing object alignment is inadquate; allocate new space
|
||||||
|
* and copy.
|
||||||
|
*/
|
||||||
|
if (no_move)
|
||||||
|
return (NULL);
|
||||||
|
usize = sa2u(size + extra, alignment, NULL);
|
||||||
|
if (usize == 0)
|
||||||
|
return (NULL);
|
||||||
|
ret = ipalloc(usize, alignment, zero);
|
||||||
|
if (ret == NULL) {
|
||||||
|
if (extra == 0)
|
||||||
|
return (NULL);
|
||||||
|
/* Try again, without extra this time. */
|
||||||
|
usize = sa2u(size, alignment, NULL);
|
||||||
|
if (usize == 0)
|
||||||
|
return (NULL);
|
||||||
|
ret = ipalloc(usize, alignment, zero);
|
||||||
|
if (ret == 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(ret, ptr, copysize);
|
||||||
|
idalloc(ptr);
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (no_move) {
|
||||||
|
if (size <= arena_maxclass) {
|
||||||
|
return (arena_ralloc_no_move(ptr, oldsize, size,
|
||||||
|
extra, zero));
|
||||||
|
} else {
|
||||||
|
return (huge_ralloc_no_move(ptr, oldsize, size,
|
||||||
|
extra));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (size + extra <= arena_maxclass) {
|
||||||
|
return (arena_ralloc(ptr, oldsize, size, extra,
|
||||||
|
alignment, zero));
|
||||||
|
} else {
|
||||||
|
return (huge_ralloc(ptr, oldsize, size, extra,
|
||||||
|
alignment, zero));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "jemalloc/internal/prof.h"
|
||||||
|
|
||||||
#undef JEMALLOC_H_INLINES
|
#undef JEMALLOC_H_INLINES
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
void mb_write(void);
|
void mb_write(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(MB_C_))
|
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_MB_C_))
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
/*
|
/*
|
||||||
* According to the Intel Architecture Software Developer's Manual, current
|
* According to the Intel Architecture Software Developer's Manual, current
|
||||||
@@ -1,7 +1,17 @@
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
#ifdef JEMALLOC_H_TYPES
|
#ifdef JEMALLOC_H_TYPES
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_OSSPIN
|
||||||
|
typedef OSSpinLock malloc_mutex_t;
|
||||||
|
#else
|
||||||
typedef pthread_mutex_t malloc_mutex_t;
|
typedef pthread_mutex_t malloc_mutex_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
|
||||||
|
# define MALLOC_MUTEX_INITIALIZER PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
|
||||||
|
#else
|
||||||
|
# define MALLOC_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* JEMALLOC_H_TYPES */
|
#endif /* JEMALLOC_H_TYPES */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@@ -18,6 +28,7 @@ extern bool isthreaded;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool malloc_mutex_init(malloc_mutex_t *mutex);
|
bool malloc_mutex_init(malloc_mutex_t *mutex);
|
||||||
|
void malloc_mutex_destroy(malloc_mutex_t *mutex);
|
||||||
|
|
||||||
#endif /* JEMALLOC_H_EXTERNS */
|
#endif /* JEMALLOC_H_EXTERNS */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@@ -25,6 +36,7 @@ bool malloc_mutex_init(malloc_mutex_t *mutex);
|
|||||||
|
|
||||||
#ifndef JEMALLOC_ENABLE_INLINE
|
#ifndef JEMALLOC_ENABLE_INLINE
|
||||||
void malloc_mutex_lock(malloc_mutex_t *mutex);
|
void malloc_mutex_lock(malloc_mutex_t *mutex);
|
||||||
|
bool malloc_mutex_trylock(malloc_mutex_t *mutex);
|
||||||
void malloc_mutex_unlock(malloc_mutex_t *mutex);
|
void malloc_mutex_unlock(malloc_mutex_t *mutex);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -33,16 +45,40 @@ JEMALLOC_INLINE void
|
|||||||
malloc_mutex_lock(malloc_mutex_t *mutex)
|
malloc_mutex_lock(malloc_mutex_t *mutex)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (isthreaded)
|
if (isthreaded) {
|
||||||
|
#ifdef JEMALLOC_OSSPIN
|
||||||
|
OSSpinLockLock(mutex);
|
||||||
|
#else
|
||||||
pthread_mutex_lock(mutex);
|
pthread_mutex_lock(mutex);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE bool
|
||||||
|
malloc_mutex_trylock(malloc_mutex_t *mutex)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (isthreaded) {
|
||||||
|
#ifdef JEMALLOC_OSSPIN
|
||||||
|
return (OSSpinLockTry(mutex) == false);
|
||||||
|
#else
|
||||||
|
return (pthread_mutex_trylock(mutex) != 0);
|
||||||
|
#endif
|
||||||
|
} else
|
||||||
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_INLINE void
|
JEMALLOC_INLINE void
|
||||||
malloc_mutex_unlock(malloc_mutex_t *mutex)
|
malloc_mutex_unlock(malloc_mutex_t *mutex)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (isthreaded)
|
if (isthreaded) {
|
||||||
|
#ifdef JEMALLOC_OSSPIN
|
||||||
|
OSSpinLockUnlock(mutex);
|
||||||
|
#else
|
||||||
pthread_mutex_unlock(mutex);
|
pthread_mutex_unlock(mutex);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
196
include/jemalloc/internal/private_namespace.h
Normal file
196
include/jemalloc/internal/private_namespace.h
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
#define arena_bin_index JEMALLOC_N(arena_bin_index)
|
||||||
|
#define arena_boot JEMALLOC_N(arena_boot)
|
||||||
|
#define arena_dalloc JEMALLOC_N(arena_dalloc)
|
||||||
|
#define arena_dalloc_bin JEMALLOC_N(arena_dalloc_bin)
|
||||||
|
#define arena_dalloc_large JEMALLOC_N(arena_dalloc_large)
|
||||||
|
#define arena_malloc JEMALLOC_N(arena_malloc)
|
||||||
|
#define arena_malloc_large JEMALLOC_N(arena_malloc_large)
|
||||||
|
#define arena_malloc_small JEMALLOC_N(arena_malloc_small)
|
||||||
|
#define arena_new JEMALLOC_N(arena_new)
|
||||||
|
#define arena_palloc JEMALLOC_N(arena_palloc)
|
||||||
|
#define arena_prof_accum JEMALLOC_N(arena_prof_accum)
|
||||||
|
#define arena_prof_ctx_get JEMALLOC_N(arena_prof_ctx_get)
|
||||||
|
#define arena_prof_ctx_set JEMALLOC_N(arena_prof_ctx_set)
|
||||||
|
#define arena_prof_promoted JEMALLOC_N(arena_prof_promoted)
|
||||||
|
#define arena_purge_all JEMALLOC_N(arena_purge_all)
|
||||||
|
#define arena_ralloc JEMALLOC_N(arena_ralloc)
|
||||||
|
#define arena_ralloc_no_move JEMALLOC_N(arena_ralloc_no_move)
|
||||||
|
#define arena_run_regind JEMALLOC_N(arena_run_regind)
|
||||||
|
#define arena_salloc JEMALLOC_N(arena_salloc)
|
||||||
|
#define arena_salloc_demote JEMALLOC_N(arena_salloc_demote)
|
||||||
|
#define arena_stats_merge JEMALLOC_N(arena_stats_merge)
|
||||||
|
#define arena_tcache_fill_small JEMALLOC_N(arena_tcache_fill_small)
|
||||||
|
#define arenas_bin_i_index JEMALLOC_N(arenas_bin_i_index)
|
||||||
|
#define arenas_extend JEMALLOC_N(arenas_extend)
|
||||||
|
#define arenas_lrun_i_index JEMALLOC_N(arenas_lrun_i_index)
|
||||||
|
#define atomic_add_uint32 JEMALLOC_N(atomic_add_uint32)
|
||||||
|
#define atomic_add_uint64 JEMALLOC_N(atomic_add_uint64)
|
||||||
|
#define atomic_sub_uint32 JEMALLOC_N(atomic_sub_uint32)
|
||||||
|
#define atomic_sub_uint64 JEMALLOC_N(atomic_sub_uint64)
|
||||||
|
#define base_alloc JEMALLOC_N(base_alloc)
|
||||||
|
#define base_boot JEMALLOC_N(base_boot)
|
||||||
|
#define base_node_alloc JEMALLOC_N(base_node_alloc)
|
||||||
|
#define base_node_dealloc JEMALLOC_N(base_node_dealloc)
|
||||||
|
#define bitmap_full JEMALLOC_N(bitmap_full)
|
||||||
|
#define bitmap_get JEMALLOC_N(bitmap_get)
|
||||||
|
#define bitmap_info_init JEMALLOC_N(bitmap_info_init)
|
||||||
|
#define bitmap_info_ngroups JEMALLOC_N(bitmap_info_ngroups)
|
||||||
|
#define bitmap_init JEMALLOC_N(bitmap_init)
|
||||||
|
#define bitmap_set JEMALLOC_N(bitmap_set)
|
||||||
|
#define bitmap_sfu JEMALLOC_N(bitmap_sfu)
|
||||||
|
#define bitmap_size JEMALLOC_N(bitmap_size)
|
||||||
|
#define bitmap_unset JEMALLOC_N(bitmap_unset)
|
||||||
|
#define bt_init JEMALLOC_N(bt_init)
|
||||||
|
#define buferror JEMALLOC_N(buferror)
|
||||||
|
#define choose_arena JEMALLOC_N(choose_arena)
|
||||||
|
#define choose_arena_hard JEMALLOC_N(choose_arena_hard)
|
||||||
|
#define chunk_alloc JEMALLOC_N(chunk_alloc)
|
||||||
|
#define chunk_alloc_dss JEMALLOC_N(chunk_alloc_dss)
|
||||||
|
#define chunk_alloc_mmap JEMALLOC_N(chunk_alloc_mmap)
|
||||||
|
#define chunk_alloc_mmap_noreserve JEMALLOC_N(chunk_alloc_mmap_noreserve)
|
||||||
|
#define chunk_alloc_swap JEMALLOC_N(chunk_alloc_swap)
|
||||||
|
#define chunk_boot JEMALLOC_N(chunk_boot)
|
||||||
|
#define chunk_dealloc JEMALLOC_N(chunk_dealloc)
|
||||||
|
#define chunk_dealloc_dss JEMALLOC_N(chunk_dealloc_dss)
|
||||||
|
#define chunk_dealloc_mmap JEMALLOC_N(chunk_dealloc_mmap)
|
||||||
|
#define chunk_dealloc_swap JEMALLOC_N(chunk_dealloc_swap)
|
||||||
|
#define chunk_dss_boot JEMALLOC_N(chunk_dss_boot)
|
||||||
|
#define chunk_in_dss JEMALLOC_N(chunk_in_dss)
|
||||||
|
#define chunk_in_swap JEMALLOC_N(chunk_in_swap)
|
||||||
|
#define chunk_mmap_boot JEMALLOC_N(chunk_mmap_boot)
|
||||||
|
#define chunk_swap_boot JEMALLOC_N(chunk_swap_boot)
|
||||||
|
#define chunk_swap_enable JEMALLOC_N(chunk_swap_enable)
|
||||||
|
#define ckh_bucket_search JEMALLOC_N(ckh_bucket_search)
|
||||||
|
#define ckh_count JEMALLOC_N(ckh_count)
|
||||||
|
#define ckh_delete JEMALLOC_N(ckh_delete)
|
||||||
|
#define ckh_evict_reloc_insert JEMALLOC_N(ckh_evict_reloc_insert)
|
||||||
|
#define ckh_insert JEMALLOC_N(ckh_insert)
|
||||||
|
#define ckh_isearch JEMALLOC_N(ckh_isearch)
|
||||||
|
#define ckh_iter JEMALLOC_N(ckh_iter)
|
||||||
|
#define ckh_new JEMALLOC_N(ckh_new)
|
||||||
|
#define ckh_pointer_hash JEMALLOC_N(ckh_pointer_hash)
|
||||||
|
#define ckh_pointer_keycomp JEMALLOC_N(ckh_pointer_keycomp)
|
||||||
|
#define ckh_rebuild JEMALLOC_N(ckh_rebuild)
|
||||||
|
#define ckh_remove JEMALLOC_N(ckh_remove)
|
||||||
|
#define ckh_search JEMALLOC_N(ckh_search)
|
||||||
|
#define ckh_string_hash JEMALLOC_N(ckh_string_hash)
|
||||||
|
#define ckh_string_keycomp JEMALLOC_N(ckh_string_keycomp)
|
||||||
|
#define ckh_try_bucket_insert JEMALLOC_N(ckh_try_bucket_insert)
|
||||||
|
#define ckh_try_insert JEMALLOC_N(ckh_try_insert)
|
||||||
|
#define create_zone JEMALLOC_N(create_zone)
|
||||||
|
#define ctl_boot JEMALLOC_N(ctl_boot)
|
||||||
|
#define ctl_bymib JEMALLOC_N(ctl_bymib)
|
||||||
|
#define ctl_byname JEMALLOC_N(ctl_byname)
|
||||||
|
#define ctl_nametomib JEMALLOC_N(ctl_nametomib)
|
||||||
|
#define extent_tree_ad_first JEMALLOC_N(extent_tree_ad_first)
|
||||||
|
#define extent_tree_ad_insert JEMALLOC_N(extent_tree_ad_insert)
|
||||||
|
#define extent_tree_ad_iter JEMALLOC_N(extent_tree_ad_iter)
|
||||||
|
#define extent_tree_ad_iter_recurse JEMALLOC_N(extent_tree_ad_iter_recurse)
|
||||||
|
#define extent_tree_ad_iter_start JEMALLOC_N(extent_tree_ad_iter_start)
|
||||||
|
#define extent_tree_ad_last JEMALLOC_N(extent_tree_ad_last)
|
||||||
|
#define extent_tree_ad_new JEMALLOC_N(extent_tree_ad_new)
|
||||||
|
#define extent_tree_ad_next JEMALLOC_N(extent_tree_ad_next)
|
||||||
|
#define extent_tree_ad_nsearch JEMALLOC_N(extent_tree_ad_nsearch)
|
||||||
|
#define extent_tree_ad_prev JEMALLOC_N(extent_tree_ad_prev)
|
||||||
|
#define extent_tree_ad_psearch JEMALLOC_N(extent_tree_ad_psearch)
|
||||||
|
#define extent_tree_ad_remove JEMALLOC_N(extent_tree_ad_remove)
|
||||||
|
#define extent_tree_ad_reverse_iter JEMALLOC_N(extent_tree_ad_reverse_iter)
|
||||||
|
#define extent_tree_ad_reverse_iter_recurse JEMALLOC_N(extent_tree_ad_reverse_iter_recurse)
|
||||||
|
#define extent_tree_ad_reverse_iter_start JEMALLOC_N(extent_tree_ad_reverse_iter_start)
|
||||||
|
#define extent_tree_ad_search JEMALLOC_N(extent_tree_ad_search)
|
||||||
|
#define extent_tree_szad_first JEMALLOC_N(extent_tree_szad_first)
|
||||||
|
#define extent_tree_szad_insert JEMALLOC_N(extent_tree_szad_insert)
|
||||||
|
#define extent_tree_szad_iter JEMALLOC_N(extent_tree_szad_iter)
|
||||||
|
#define extent_tree_szad_iter_recurse JEMALLOC_N(extent_tree_szad_iter_recurse)
|
||||||
|
#define extent_tree_szad_iter_start JEMALLOC_N(extent_tree_szad_iter_start)
|
||||||
|
#define extent_tree_szad_last JEMALLOC_N(extent_tree_szad_last)
|
||||||
|
#define extent_tree_szad_new JEMALLOC_N(extent_tree_szad_new)
|
||||||
|
#define extent_tree_szad_next JEMALLOC_N(extent_tree_szad_next)
|
||||||
|
#define extent_tree_szad_nsearch JEMALLOC_N(extent_tree_szad_nsearch)
|
||||||
|
#define extent_tree_szad_prev JEMALLOC_N(extent_tree_szad_prev)
|
||||||
|
#define extent_tree_szad_psearch JEMALLOC_N(extent_tree_szad_psearch)
|
||||||
|
#define extent_tree_szad_remove JEMALLOC_N(extent_tree_szad_remove)
|
||||||
|
#define extent_tree_szad_reverse_iter JEMALLOC_N(extent_tree_szad_reverse_iter)
|
||||||
|
#define extent_tree_szad_reverse_iter_recurse JEMALLOC_N(extent_tree_szad_reverse_iter_recurse)
|
||||||
|
#define extent_tree_szad_reverse_iter_start JEMALLOC_N(extent_tree_szad_reverse_iter_start)
|
||||||
|
#define extent_tree_szad_search JEMALLOC_N(extent_tree_szad_search)
|
||||||
|
#define hash JEMALLOC_N(hash)
|
||||||
|
#define huge_boot JEMALLOC_N(huge_boot)
|
||||||
|
#define huge_dalloc JEMALLOC_N(huge_dalloc)
|
||||||
|
#define huge_malloc JEMALLOC_N(huge_malloc)
|
||||||
|
#define huge_palloc JEMALLOC_N(huge_palloc)
|
||||||
|
#define huge_prof_ctx_get JEMALLOC_N(huge_prof_ctx_get)
|
||||||
|
#define huge_prof_ctx_set JEMALLOC_N(huge_prof_ctx_set)
|
||||||
|
#define huge_ralloc JEMALLOC_N(huge_ralloc)
|
||||||
|
#define huge_ralloc_no_move JEMALLOC_N(huge_ralloc_no_move)
|
||||||
|
#define huge_salloc JEMALLOC_N(huge_salloc)
|
||||||
|
#define iallocm JEMALLOC_N(iallocm)
|
||||||
|
#define icalloc JEMALLOC_N(icalloc)
|
||||||
|
#define idalloc JEMALLOC_N(idalloc)
|
||||||
|
#define imalloc JEMALLOC_N(imalloc)
|
||||||
|
#define ipalloc JEMALLOC_N(ipalloc)
|
||||||
|
#define iralloc JEMALLOC_N(iralloc)
|
||||||
|
#define isalloc JEMALLOC_N(isalloc)
|
||||||
|
#define ivsalloc JEMALLOC_N(ivsalloc)
|
||||||
|
#define jemalloc_darwin_init JEMALLOC_N(jemalloc_darwin_init)
|
||||||
|
#define jemalloc_postfork JEMALLOC_N(jemalloc_postfork)
|
||||||
|
#define jemalloc_prefork JEMALLOC_N(jemalloc_prefork)
|
||||||
|
#define malloc_cprintf JEMALLOC_N(malloc_cprintf)
|
||||||
|
#define malloc_mutex_destroy JEMALLOC_N(malloc_mutex_destroy)
|
||||||
|
#define malloc_mutex_init JEMALLOC_N(malloc_mutex_init)
|
||||||
|
#define malloc_mutex_lock JEMALLOC_N(malloc_mutex_lock)
|
||||||
|
#define malloc_mutex_trylock JEMALLOC_N(malloc_mutex_trylock)
|
||||||
|
#define malloc_mutex_unlock JEMALLOC_N(malloc_mutex_unlock)
|
||||||
|
#define malloc_printf JEMALLOC_N(malloc_printf)
|
||||||
|
#define malloc_write JEMALLOC_N(malloc_write)
|
||||||
|
#define mb_write JEMALLOC_N(mb_write)
|
||||||
|
#define pow2_ceil JEMALLOC_N(pow2_ceil)
|
||||||
|
#define prof_alloc_prep JEMALLOC_N(prof_alloc_prep)
|
||||||
|
#define prof_backtrace JEMALLOC_N(prof_backtrace)
|
||||||
|
#define prof_boot0 JEMALLOC_N(prof_boot0)
|
||||||
|
#define prof_boot1 JEMALLOC_N(prof_boot1)
|
||||||
|
#define prof_boot2 JEMALLOC_N(prof_boot2)
|
||||||
|
#define prof_ctx_get JEMALLOC_N(prof_ctx_get)
|
||||||
|
#define prof_ctx_set JEMALLOC_N(prof_ctx_set)
|
||||||
|
#define prof_free JEMALLOC_N(prof_free)
|
||||||
|
#define prof_gdump JEMALLOC_N(prof_gdump)
|
||||||
|
#define prof_idump JEMALLOC_N(prof_idump)
|
||||||
|
#define prof_lookup JEMALLOC_N(prof_lookup)
|
||||||
|
#define prof_malloc JEMALLOC_N(prof_malloc)
|
||||||
|
#define prof_mdump JEMALLOC_N(prof_mdump)
|
||||||
|
#define prof_realloc JEMALLOC_N(prof_realloc)
|
||||||
|
#define prof_sample_accum_update JEMALLOC_N(prof_sample_accum_update)
|
||||||
|
#define prof_sample_threshold_update JEMALLOC_N(prof_sample_threshold_update)
|
||||||
|
#define prof_tdata_init JEMALLOC_N(prof_tdata_init)
|
||||||
|
#define pthread_create JEMALLOC_N(pthread_create)
|
||||||
|
#define rtree_get JEMALLOC_N(rtree_get)
|
||||||
|
#define rtree_get_locked JEMALLOC_N(rtree_get_locked)
|
||||||
|
#define rtree_new JEMALLOC_N(rtree_new)
|
||||||
|
#define rtree_set JEMALLOC_N(rtree_set)
|
||||||
|
#define s2u JEMALLOC_N(s2u)
|
||||||
|
#define sa2u JEMALLOC_N(sa2u)
|
||||||
|
#define stats_arenas_i_bins_j_index JEMALLOC_N(stats_arenas_i_bins_j_index)
|
||||||
|
#define stats_arenas_i_index JEMALLOC_N(stats_arenas_i_index)
|
||||||
|
#define stats_arenas_i_lruns_j_index JEMALLOC_N(stats_arenas_i_lruns_j_index)
|
||||||
|
#define stats_cactive_add JEMALLOC_N(stats_cactive_add)
|
||||||
|
#define stats_cactive_get JEMALLOC_N(stats_cactive_get)
|
||||||
|
#define stats_cactive_sub JEMALLOC_N(stats_cactive_sub)
|
||||||
|
#define stats_print JEMALLOC_N(stats_print)
|
||||||
|
#define szone2ozone JEMALLOC_N(szone2ozone)
|
||||||
|
#define tcache_alloc_easy JEMALLOC_N(tcache_alloc_easy)
|
||||||
|
#define tcache_alloc_large JEMALLOC_N(tcache_alloc_large)
|
||||||
|
#define tcache_alloc_small JEMALLOC_N(tcache_alloc_small)
|
||||||
|
#define tcache_alloc_small_hard JEMALLOC_N(tcache_alloc_small_hard)
|
||||||
|
#define tcache_bin_flush_large JEMALLOC_N(tcache_bin_flush_large)
|
||||||
|
#define tcache_bin_flush_small JEMALLOC_N(tcache_bin_flush_small)
|
||||||
|
#define tcache_boot JEMALLOC_N(tcache_boot)
|
||||||
|
#define tcache_create JEMALLOC_N(tcache_create)
|
||||||
|
#define tcache_dalloc_large JEMALLOC_N(tcache_dalloc_large)
|
||||||
|
#define tcache_dalloc_small JEMALLOC_N(tcache_dalloc_small)
|
||||||
|
#define tcache_destroy JEMALLOC_N(tcache_destroy)
|
||||||
|
#define tcache_event JEMALLOC_N(tcache_event)
|
||||||
|
#define tcache_get JEMALLOC_N(tcache_get)
|
||||||
|
#define tcache_stats_merge JEMALLOC_N(tcache_stats_merge)
|
||||||
|
#define thread_allocated_get JEMALLOC_N(thread_allocated_get)
|
||||||
|
#define thread_allocated_get_hard JEMALLOC_N(thread_allocated_get_hard)
|
||||||
|
#define u2s JEMALLOC_N(u2s)
|
||||||
561
include/jemalloc/internal/prof.h
Normal file
561
include/jemalloc/internal/prof.h
Normal file
@@ -0,0 +1,561 @@
|
|||||||
|
#ifdef JEMALLOC_PROF
|
||||||
|
/******************************************************************************/
|
||||||
|
#ifdef JEMALLOC_H_TYPES
|
||||||
|
|
||||||
|
typedef struct prof_bt_s prof_bt_t;
|
||||||
|
typedef struct prof_cnt_s prof_cnt_t;
|
||||||
|
typedef struct prof_thr_cnt_s prof_thr_cnt_t;
|
||||||
|
typedef struct prof_ctx_s prof_ctx_t;
|
||||||
|
typedef struct prof_tdata_s prof_tdata_t;
|
||||||
|
|
||||||
|
/* Option defaults. */
|
||||||
|
#define PROF_PREFIX_DEFAULT "jeprof"
|
||||||
|
#define LG_PROF_BT_MAX_DEFAULT 7
|
||||||
|
#define LG_PROF_SAMPLE_DEFAULT 0
|
||||||
|
#define LG_PROF_INTERVAL_DEFAULT -1
|
||||||
|
#define LG_PROF_TCMAX_DEFAULT -1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hard limit on stack backtrace depth. Note that the version of
|
||||||
|
* prof_backtrace() that is based on __builtin_return_address() necessarily has
|
||||||
|
* a hard-coded number of backtrace frame handlers.
|
||||||
|
*/
|
||||||
|
#if (defined(JEMALLOC_PROF_LIBGCC) || defined(JEMALLOC_PROF_LIBUNWIND))
|
||||||
|
# define LG_PROF_BT_MAX ((ZU(1) << (LG_SIZEOF_PTR+3)) - 1)
|
||||||
|
#else
|
||||||
|
# define LG_PROF_BT_MAX 7 /* >= LG_PROF_BT_MAX_DEFAULT */
|
||||||
|
#endif
|
||||||
|
#define PROF_BT_MAX (1U << LG_PROF_BT_MAX)
|
||||||
|
|
||||||
|
/* Initial hash table size. */
|
||||||
|
#define PROF_CKH_MINITEMS 64
|
||||||
|
|
||||||
|
/* Size of memory buffer to use when writing dump files. */
|
||||||
|
#define PROF_DUMP_BUF_SIZE 65536
|
||||||
|
|
||||||
|
#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 nignore;
|
||||||
|
unsigned max;
|
||||||
|
} prof_unwind_data_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct prof_cnt_s {
|
||||||
|
/*
|
||||||
|
* Profiling counters. An allocation/deallocation pair can operate on
|
||||||
|
* different prof_thr_cnt_t objects that are linked into the same
|
||||||
|
* prof_ctx_t cnts_ql, so it is possible for the cur* counters to go
|
||||||
|
* negative. In principle it is possible for the *bytes counters to
|
||||||
|
* overflow/underflow, but a general solution would require something
|
||||||
|
* like 128-bit counters; this implementation doesn't bother to solve
|
||||||
|
* that problem.
|
||||||
|
*/
|
||||||
|
int64_t curobjs;
|
||||||
|
int64_t curbytes;
|
||||||
|
uint64_t accumobjs;
|
||||||
|
uint64_t accumbytes;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct prof_thr_cnt_s {
|
||||||
|
/* Linkage into prof_ctx_t's cnts_ql. */
|
||||||
|
ql_elm(prof_thr_cnt_t) cnts_link;
|
||||||
|
|
||||||
|
/* Linkage into thread's LRU. */
|
||||||
|
ql_elm(prof_thr_cnt_t) lru_link;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Associated context. If a thread frees an object that it did not
|
||||||
|
* allocate, it is possible that the context is not cached in the
|
||||||
|
* thread's hash table, in which case it must be able to look up the
|
||||||
|
* context, insert a new prof_thr_cnt_t into the thread's hash table,
|
||||||
|
* and link it into the prof_ctx_t's cnts_ql.
|
||||||
|
*/
|
||||||
|
prof_ctx_t *ctx;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Threads use memory barriers to update the counters. Since there is
|
||||||
|
* only ever one writer, the only challenge is for the reader to get a
|
||||||
|
* consistent read of the counters.
|
||||||
|
*
|
||||||
|
* The writer uses this series of operations:
|
||||||
|
*
|
||||||
|
* 1) Increment epoch to an odd number.
|
||||||
|
* 2) Update counters.
|
||||||
|
* 3) Increment epoch to an even number.
|
||||||
|
*
|
||||||
|
* The reader must assure 1) that the epoch is even while it reads the
|
||||||
|
* counters, and 2) that the epoch doesn't change between the time it
|
||||||
|
* starts and finishes reading the counters.
|
||||||
|
*/
|
||||||
|
unsigned epoch;
|
||||||
|
|
||||||
|
/* Profiling counters. */
|
||||||
|
prof_cnt_t cnts;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct prof_ctx_s {
|
||||||
|
/* Associated backtrace. */
|
||||||
|
prof_bt_t *bt;
|
||||||
|
|
||||||
|
/* Protects cnt_merged and cnts_ql. */
|
||||||
|
malloc_mutex_t lock;
|
||||||
|
|
||||||
|
/* Temporary storage for summation during dump. */
|
||||||
|
prof_cnt_t cnt_summed;
|
||||||
|
|
||||||
|
/* When threads exit, they merge their stats into cnt_merged. */
|
||||||
|
prof_cnt_t cnt_merged;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List of profile counters, one for each thread that has allocated in
|
||||||
|
* this context.
|
||||||
|
*/
|
||||||
|
ql_head(prof_thr_cnt_t) cnts_ql;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct prof_tdata_s {
|
||||||
|
/*
|
||||||
|
* Hash of (prof_bt_t *)-->(prof_thr_cnt_t *). Each thread keeps a
|
||||||
|
* cache of backtraces, with associated thread-specific prof_thr_cnt_t
|
||||||
|
* objects. Other threads may read the prof_thr_cnt_t contents, but no
|
||||||
|
* others will ever write them.
|
||||||
|
*
|
||||||
|
* Upon thread exit, the thread must merge all the prof_thr_cnt_t
|
||||||
|
* counter data into the associated prof_ctx_t objects, and unlink/free
|
||||||
|
* the prof_thr_cnt_t objects.
|
||||||
|
*/
|
||||||
|
ckh_t bt2cnt;
|
||||||
|
|
||||||
|
/* LRU for contents of bt2cnt. */
|
||||||
|
ql_head(prof_thr_cnt_t) lru_ql;
|
||||||
|
|
||||||
|
/* Backtrace vector, used for calls to prof_backtrace(). */
|
||||||
|
void **vec;
|
||||||
|
|
||||||
|
/* Sampling state. */
|
||||||
|
uint64_t prn_state;
|
||||||
|
uint64_t threshold;
|
||||||
|
uint64_t accum;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_STRUCTS */
|
||||||
|
/******************************************************************************/
|
||||||
|
#ifdef JEMALLOC_H_EXTERNS
|
||||||
|
|
||||||
|
extern bool opt_prof;
|
||||||
|
/*
|
||||||
|
* Even if opt_prof is true, sampling can be temporarily disabled by setting
|
||||||
|
* opt_prof_active to false. No locking is used when updating opt_prof_active,
|
||||||
|
* so there are no guarantees regarding how long it will take for all threads
|
||||||
|
* to notice state changes.
|
||||||
|
*/
|
||||||
|
extern bool opt_prof_active;
|
||||||
|
extern size_t opt_lg_prof_bt_max; /* Maximum backtrace depth. */
|
||||||
|
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_leak; /* Dump leak summary at exit. */
|
||||||
|
extern bool opt_prof_accum; /* Report cumulative bytes. */
|
||||||
|
extern ssize_t opt_lg_prof_tcmax; /* lg(max per thread bactrace cache) */
|
||||||
|
extern char opt_prof_prefix[PATH_MAX + 1];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If true, promote small sampled objects to large objects, since small run
|
||||||
|
* headers do not have embedded profile context pointers.
|
||||||
|
*/
|
||||||
|
extern bool prof_promote;
|
||||||
|
|
||||||
|
/* (1U << opt_lg_prof_bt_max). */
|
||||||
|
extern unsigned prof_bt_max;
|
||||||
|
|
||||||
|
/* Thread-specific backtrace cache, used to reduce bt2ctx contention. */
|
||||||
|
#ifndef NO_TLS
|
||||||
|
extern __thread prof_tdata_t *prof_tdata_tls
|
||||||
|
JEMALLOC_ATTR(tls_model("initial-exec"));
|
||||||
|
# define PROF_TCACHE_GET() prof_tdata_tls
|
||||||
|
# define PROF_TCACHE_SET(v) do { \
|
||||||
|
prof_tdata_tls = (v); \
|
||||||
|
pthread_setspecific(prof_tdata_tsd, (void *)(v)); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
# define PROF_TCACHE_GET() \
|
||||||
|
((prof_tdata_t *)pthread_getspecific(prof_tdata_tsd))
|
||||||
|
# define PROF_TCACHE_SET(v) do { \
|
||||||
|
pthread_setspecific(prof_tdata_tsd, (void *)(v)); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Same contents as b2cnt_tls, but initialized such that the TSD destructor is
|
||||||
|
* called when a thread exits, so that prof_tdata_tls contents can be merged,
|
||||||
|
* unlinked, and deallocated.
|
||||||
|
*/
|
||||||
|
extern pthread_key_t prof_tdata_tsd;
|
||||||
|
|
||||||
|
void bt_init(prof_bt_t *bt, void **vec);
|
||||||
|
void prof_backtrace(prof_bt_t *bt, unsigned nignore, unsigned max);
|
||||||
|
prof_thr_cnt_t *prof_lookup(prof_bt_t *bt);
|
||||||
|
void prof_idump(void);
|
||||||
|
bool prof_mdump(const char *filename);
|
||||||
|
void prof_gdump(void);
|
||||||
|
prof_tdata_t *prof_tdata_init(void);
|
||||||
|
void prof_boot0(void);
|
||||||
|
void prof_boot1(void);
|
||||||
|
bool prof_boot2(void);
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_EXTERNS */
|
||||||
|
/******************************************************************************/
|
||||||
|
#ifdef JEMALLOC_H_INLINES
|
||||||
|
|
||||||
|
#ifndef JEMALLOC_ENABLE_INLINE
|
||||||
|
void prof_sample_threshold_update(prof_tdata_t *prof_tdata);
|
||||||
|
prof_thr_cnt_t *prof_alloc_prep(size_t size);
|
||||||
|
prof_ctx_t *prof_ctx_get(const void *ptr);
|
||||||
|
void prof_ctx_set(const void *ptr, prof_ctx_t *ctx);
|
||||||
|
bool prof_sample_accum_update(size_t size);
|
||||||
|
void prof_malloc(const void *ptr, size_t size, prof_thr_cnt_t *cnt);
|
||||||
|
void prof_realloc(const void *ptr, size_t size, prof_thr_cnt_t *cnt,
|
||||||
|
size_t old_size, prof_ctx_t *old_ctx);
|
||||||
|
void prof_free(const void *ptr, size_t size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_PROF_C_))
|
||||||
|
JEMALLOC_INLINE void
|
||||||
|
prof_sample_threshold_update(prof_tdata_t *prof_tdata)
|
||||||
|
{
|
||||||
|
uint64_t r;
|
||||||
|
double u;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute sample threshold as a geometrically distributed random
|
||||||
|
* variable with mean (2^opt_lg_prof_sample).
|
||||||
|
*
|
||||||
|
* __ __
|
||||||
|
* | log(u) | 1
|
||||||
|
* prof_tdata->threshold = | -------- |, where p = -------------------
|
||||||
|
* | log(1-p) | opt_lg_prof_sample
|
||||||
|
* 2
|
||||||
|
*
|
||||||
|
* For more information on the math, see:
|
||||||
|
*
|
||||||
|
* Non-Uniform Random Variate Generation
|
||||||
|
* Luc Devroye
|
||||||
|
* Springer-Verlag, New York, 1986
|
||||||
|
* pp 500
|
||||||
|
* (http://cg.scs.carleton.ca/~luc/rnbookindex.html)
|
||||||
|
*/
|
||||||
|
prn64(r, 53, prof_tdata->prn_state,
|
||||||
|
(uint64_t)6364136223846793005LLU, (uint64_t)1442695040888963407LLU);
|
||||||
|
u = (double)r * (1.0/9007199254740992.0L);
|
||||||
|
prof_tdata->threshold = (uint64_t)(log(u) /
|
||||||
|
log(1.0 - (1.0 / (double)((uint64_t)1U << opt_lg_prof_sample))))
|
||||||
|
+ (uint64_t)1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE prof_thr_cnt_t *
|
||||||
|
prof_alloc_prep(size_t size)
|
||||||
|
{
|
||||||
|
#ifdef JEMALLOC_ENABLE_INLINE
|
||||||
|
/* This function does not have its own stack frame, because it is inlined. */
|
||||||
|
# define NIGNORE 1
|
||||||
|
#else
|
||||||
|
# define NIGNORE 2
|
||||||
|
#endif
|
||||||
|
prof_thr_cnt_t *ret;
|
||||||
|
prof_tdata_t *prof_tdata;
|
||||||
|
prof_bt_t bt;
|
||||||
|
|
||||||
|
assert(size == s2u(size));
|
||||||
|
|
||||||
|
prof_tdata = PROF_TCACHE_GET();
|
||||||
|
if (prof_tdata == NULL) {
|
||||||
|
prof_tdata = prof_tdata_init();
|
||||||
|
if (prof_tdata == NULL)
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt_prof_active == false) {
|
||||||
|
/* Sampling is currently inactive, so avoid sampling. */
|
||||||
|
ret = (prof_thr_cnt_t *)(uintptr_t)1U;
|
||||||
|
} else if (opt_lg_prof_sample == 0) {
|
||||||
|
/*
|
||||||
|
* Don't bother with sampling logic, since sampling interval is
|
||||||
|
* 1.
|
||||||
|
*/
|
||||||
|
bt_init(&bt, prof_tdata->vec);
|
||||||
|
prof_backtrace(&bt, NIGNORE, prof_bt_max);
|
||||||
|
ret = prof_lookup(&bt);
|
||||||
|
} else {
|
||||||
|
if (prof_tdata->threshold == 0) {
|
||||||
|
/*
|
||||||
|
* Initialize. Seed the prng differently for each
|
||||||
|
* thread.
|
||||||
|
*/
|
||||||
|
prof_tdata->prn_state = (uint64_t)(uintptr_t)&size;
|
||||||
|
prof_sample_threshold_update(prof_tdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine whether to capture a backtrace based on whether
|
||||||
|
* size is enough for prof_accum to reach
|
||||||
|
* prof_tdata->threshold. However, delay updating these
|
||||||
|
* variables until prof_{m,re}alloc(), because we don't know
|
||||||
|
* for sure that the allocation will succeed.
|
||||||
|
*
|
||||||
|
* Use subtraction rather than addition to avoid potential
|
||||||
|
* integer overflow.
|
||||||
|
*/
|
||||||
|
if (size >= prof_tdata->threshold - prof_tdata->accum) {
|
||||||
|
bt_init(&bt, prof_tdata->vec);
|
||||||
|
prof_backtrace(&bt, NIGNORE, prof_bt_max);
|
||||||
|
ret = prof_lookup(&bt);
|
||||||
|
} else
|
||||||
|
ret = (prof_thr_cnt_t *)(uintptr_t)1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ret);
|
||||||
|
#undef NIGNORE
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE prof_ctx_t *
|
||||||
|
prof_ctx_get(const void *ptr)
|
||||||
|
{
|
||||||
|
prof_ctx_t *ret;
|
||||||
|
arena_chunk_t *chunk;
|
||||||
|
|
||||||
|
assert(ptr != NULL);
|
||||||
|
|
||||||
|
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
||||||
|
if (chunk != ptr) {
|
||||||
|
/* Region. */
|
||||||
|
dassert(chunk->arena->magic == ARENA_MAGIC);
|
||||||
|
|
||||||
|
ret = arena_prof_ctx_get(ptr);
|
||||||
|
} else
|
||||||
|
ret = huge_prof_ctx_get(ptr);
|
||||||
|
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE void
|
||||||
|
prof_ctx_set(const void *ptr, prof_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
arena_chunk_t *chunk;
|
||||||
|
|
||||||
|
assert(ptr != NULL);
|
||||||
|
|
||||||
|
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
||||||
|
if (chunk != ptr) {
|
||||||
|
/* Region. */
|
||||||
|
dassert(chunk->arena->magic == ARENA_MAGIC);
|
||||||
|
|
||||||
|
arena_prof_ctx_set(ptr, ctx);
|
||||||
|
} else
|
||||||
|
huge_prof_ctx_set(ptr, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE bool
|
||||||
|
prof_sample_accum_update(size_t size)
|
||||||
|
{
|
||||||
|
prof_tdata_t *prof_tdata;
|
||||||
|
|
||||||
|
/* Sampling logic is unnecessary if the interval is 1. */
|
||||||
|
assert(opt_lg_prof_sample != 0);
|
||||||
|
|
||||||
|
prof_tdata = PROF_TCACHE_GET();
|
||||||
|
assert(prof_tdata != NULL);
|
||||||
|
|
||||||
|
/* Take care to avoid integer overflow. */
|
||||||
|
if (size >= prof_tdata->threshold - prof_tdata->accum) {
|
||||||
|
prof_tdata->accum -= (prof_tdata->threshold - size);
|
||||||
|
/* Compute new sample threshold. */
|
||||||
|
prof_sample_threshold_update(prof_tdata);
|
||||||
|
while (prof_tdata->accum >= prof_tdata->threshold) {
|
||||||
|
prof_tdata->accum -= prof_tdata->threshold;
|
||||||
|
prof_sample_threshold_update(prof_tdata);
|
||||||
|
}
|
||||||
|
return (false);
|
||||||
|
} else {
|
||||||
|
prof_tdata->accum += size;
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE void
|
||||||
|
prof_malloc(const void *ptr, size_t size, prof_thr_cnt_t *cnt)
|
||||||
|
{
|
||||||
|
|
||||||
|
assert(ptr != NULL);
|
||||||
|
assert(size == isalloc(ptr));
|
||||||
|
|
||||||
|
if (opt_lg_prof_sample != 0) {
|
||||||
|
if (prof_sample_accum_update(size)) {
|
||||||
|
/*
|
||||||
|
* Don't sample. For malloc()-like allocation, it is
|
||||||
|
* always possible to tell in advance how large an
|
||||||
|
* object's usable size will be, so there should never
|
||||||
|
* be a difference between the size passed to
|
||||||
|
* prof_alloc_prep() and prof_malloc().
|
||||||
|
*/
|
||||||
|
assert((uintptr_t)cnt == (uintptr_t)1U);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((uintptr_t)cnt > (uintptr_t)1U) {
|
||||||
|
prof_ctx_set(ptr, cnt->ctx);
|
||||||
|
|
||||||
|
cnt->epoch++;
|
||||||
|
/*********/
|
||||||
|
mb_write();
|
||||||
|
/*********/
|
||||||
|
cnt->cnts.curobjs++;
|
||||||
|
cnt->cnts.curbytes += size;
|
||||||
|
if (opt_prof_accum) {
|
||||||
|
cnt->cnts.accumobjs++;
|
||||||
|
cnt->cnts.accumbytes += size;
|
||||||
|
}
|
||||||
|
/*********/
|
||||||
|
mb_write();
|
||||||
|
/*********/
|
||||||
|
cnt->epoch++;
|
||||||
|
/*********/
|
||||||
|
mb_write();
|
||||||
|
/*********/
|
||||||
|
} else
|
||||||
|
prof_ctx_set(ptr, (prof_ctx_t *)(uintptr_t)1U);
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE void
|
||||||
|
prof_realloc(const void *ptr, size_t size, prof_thr_cnt_t *cnt,
|
||||||
|
size_t old_size, prof_ctx_t *old_ctx)
|
||||||
|
{
|
||||||
|
prof_thr_cnt_t *told_cnt;
|
||||||
|
|
||||||
|
assert(ptr != NULL || (uintptr_t)cnt <= (uintptr_t)1U);
|
||||||
|
|
||||||
|
if (ptr != NULL) {
|
||||||
|
assert(size == isalloc(ptr));
|
||||||
|
if (opt_lg_prof_sample != 0) {
|
||||||
|
if (prof_sample_accum_update(size)) {
|
||||||
|
/*
|
||||||
|
* Don't sample. The size passed to
|
||||||
|
* prof_alloc_prep() was larger than what
|
||||||
|
* actually got allocated, so a backtrace was
|
||||||
|
* captured for this allocation, even though
|
||||||
|
* its actual size was insufficient to cross
|
||||||
|
* the sample threshold.
|
||||||
|
*/
|
||||||
|
cnt = (prof_thr_cnt_t *)(uintptr_t)1U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((uintptr_t)old_ctx > (uintptr_t)1U) {
|
||||||
|
told_cnt = prof_lookup(old_ctx->bt);
|
||||||
|
if (told_cnt == NULL) {
|
||||||
|
/*
|
||||||
|
* It's too late to propagate OOM for this realloc(),
|
||||||
|
* so operate directly on old_cnt->ctx->cnt_merged.
|
||||||
|
*/
|
||||||
|
malloc_mutex_lock(&old_ctx->lock);
|
||||||
|
old_ctx->cnt_merged.curobjs--;
|
||||||
|
old_ctx->cnt_merged.curbytes -= old_size;
|
||||||
|
malloc_mutex_unlock(&old_ctx->lock);
|
||||||
|
told_cnt = (prof_thr_cnt_t *)(uintptr_t)1U;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
told_cnt = (prof_thr_cnt_t *)(uintptr_t)1U;
|
||||||
|
|
||||||
|
if ((uintptr_t)told_cnt > (uintptr_t)1U)
|
||||||
|
told_cnt->epoch++;
|
||||||
|
if ((uintptr_t)cnt > (uintptr_t)1U) {
|
||||||
|
prof_ctx_set(ptr, cnt->ctx);
|
||||||
|
cnt->epoch++;
|
||||||
|
} else
|
||||||
|
prof_ctx_set(ptr, (prof_ctx_t *)(uintptr_t)1U);
|
||||||
|
/*********/
|
||||||
|
mb_write();
|
||||||
|
/*********/
|
||||||
|
if ((uintptr_t)told_cnt > (uintptr_t)1U) {
|
||||||
|
told_cnt->cnts.curobjs--;
|
||||||
|
told_cnt->cnts.curbytes -= old_size;
|
||||||
|
}
|
||||||
|
if ((uintptr_t)cnt > (uintptr_t)1U) {
|
||||||
|
cnt->cnts.curobjs++;
|
||||||
|
cnt->cnts.curbytes += size;
|
||||||
|
if (opt_prof_accum) {
|
||||||
|
cnt->cnts.accumobjs++;
|
||||||
|
cnt->cnts.accumbytes += size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*********/
|
||||||
|
mb_write();
|
||||||
|
/*********/
|
||||||
|
if ((uintptr_t)told_cnt > (uintptr_t)1U)
|
||||||
|
told_cnt->epoch++;
|
||||||
|
if ((uintptr_t)cnt > (uintptr_t)1U)
|
||||||
|
cnt->epoch++;
|
||||||
|
/*********/
|
||||||
|
mb_write(); /* Not strictly necessary. */
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE void
|
||||||
|
prof_free(const void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
prof_ctx_t *ctx = prof_ctx_get(ptr);
|
||||||
|
|
||||||
|
if ((uintptr_t)ctx > (uintptr_t)1) {
|
||||||
|
assert(size == isalloc(ptr));
|
||||||
|
prof_thr_cnt_t *tcnt = prof_lookup(ctx->bt);
|
||||||
|
|
||||||
|
if (tcnt != NULL) {
|
||||||
|
tcnt->epoch++;
|
||||||
|
/*********/
|
||||||
|
mb_write();
|
||||||
|
/*********/
|
||||||
|
tcnt->cnts.curobjs--;
|
||||||
|
tcnt->cnts.curbytes -= size;
|
||||||
|
/*********/
|
||||||
|
mb_write();
|
||||||
|
/*********/
|
||||||
|
tcnt->epoch++;
|
||||||
|
/*********/
|
||||||
|
mb_write();
|
||||||
|
/*********/
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* OOM during free() cannot be propagated, so operate
|
||||||
|
* directly on cnt->ctx->cnt_merged.
|
||||||
|
*/
|
||||||
|
malloc_mutex_lock(&ctx->lock);
|
||||||
|
ctx->cnt_merged.curobjs--;
|
||||||
|
ctx->cnt_merged.curbytes -= size;
|
||||||
|
malloc_mutex_unlock(&ctx->lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_INLINES */
|
||||||
|
/******************************************************************************/
|
||||||
|
#endif /* JEMALLOC_PROF */
|
||||||
161
include/jemalloc/internal/rtree.h
Normal file
161
include/jemalloc/internal/rtree.h
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* This radix tree implementation is tailored to the singular purpose of
|
||||||
|
* tracking which chunks are currently owned by jemalloc. This functionality
|
||||||
|
* is mandatory for OS X, where jemalloc must be able to respond to object
|
||||||
|
* ownership queries.
|
||||||
|
*
|
||||||
|
*******************************************************************************
|
||||||
|
*/
|
||||||
|
#ifdef JEMALLOC_H_TYPES
|
||||||
|
|
||||||
|
typedef struct rtree_s rtree_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Size of each radix tree node (must be a power of 2). This impacts tree
|
||||||
|
* depth.
|
||||||
|
*/
|
||||||
|
#if (LG_SIZEOF_PTR == 2)
|
||||||
|
# define RTREE_NODESIZE (1U << 14)
|
||||||
|
#else
|
||||||
|
# define RTREE_NODESIZE CACHELINE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_TYPES */
|
||||||
|
/******************************************************************************/
|
||||||
|
#ifdef JEMALLOC_H_STRUCTS
|
||||||
|
|
||||||
|
struct rtree_s {
|
||||||
|
malloc_mutex_t mutex;
|
||||||
|
void **root;
|
||||||
|
unsigned height;
|
||||||
|
unsigned level2bits[1]; /* Dynamically sized. */
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_STRUCTS */
|
||||||
|
/******************************************************************************/
|
||||||
|
#ifdef JEMALLOC_H_EXTERNS
|
||||||
|
|
||||||
|
rtree_t *rtree_new(unsigned bits);
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_EXTERNS */
|
||||||
|
/******************************************************************************/
|
||||||
|
#ifdef JEMALLOC_H_INLINES
|
||||||
|
|
||||||
|
#ifndef JEMALLOC_ENABLE_INLINE
|
||||||
|
#ifndef JEMALLOC_DEBUG
|
||||||
|
void *rtree_get_locked(rtree_t *rtree, uintptr_t key);
|
||||||
|
#endif
|
||||||
|
void *rtree_get(rtree_t *rtree, uintptr_t key);
|
||||||
|
bool rtree_set(rtree_t *rtree, uintptr_t key, void *val);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_RTREE_C_))
|
||||||
|
#define RTREE_GET_GENERATE(f) \
|
||||||
|
/* The least significant bits of the key are ignored. */ \
|
||||||
|
JEMALLOC_INLINE void * \
|
||||||
|
f(rtree_t *rtree, uintptr_t key) \
|
||||||
|
{ \
|
||||||
|
void *ret; \
|
||||||
|
uintptr_t subkey; \
|
||||||
|
unsigned i, lshift, height, bits; \
|
||||||
|
void **node, **child; \
|
||||||
|
\
|
||||||
|
RTREE_LOCK(&rtree->mutex); \
|
||||||
|
for (i = lshift = 0, height = rtree->height, node = rtree->root;\
|
||||||
|
i < height - 1; \
|
||||||
|
i++, lshift += bits, node = child) { \
|
||||||
|
bits = rtree->level2bits[i]; \
|
||||||
|
subkey = (key << lshift) >> ((ZU(1) << (LG_SIZEOF_PTR + \
|
||||||
|
3)) - bits); \
|
||||||
|
child = (void**)node[subkey]; \
|
||||||
|
if (child == NULL) { \
|
||||||
|
RTREE_UNLOCK(&rtree->mutex); \
|
||||||
|
return (NULL); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* \
|
||||||
|
* node is a leaf, so it contains values rather than node \
|
||||||
|
* pointers. \
|
||||||
|
*/ \
|
||||||
|
bits = rtree->level2bits[i]; \
|
||||||
|
subkey = (key << lshift) >> ((ZU(1) << (LG_SIZEOF_PTR+3)) - \
|
||||||
|
bits); \
|
||||||
|
ret = node[subkey]; \
|
||||||
|
RTREE_UNLOCK(&rtree->mutex); \
|
||||||
|
\
|
||||||
|
RTREE_GET_VALIDATE \
|
||||||
|
return (ret); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_DEBUG
|
||||||
|
# define RTREE_LOCK(l) malloc_mutex_lock(l)
|
||||||
|
# define RTREE_UNLOCK(l) malloc_mutex_unlock(l)
|
||||||
|
# define RTREE_GET_VALIDATE
|
||||||
|
RTREE_GET_GENERATE(rtree_get_locked)
|
||||||
|
# undef RTREE_LOCK
|
||||||
|
# undef RTREE_UNLOCK
|
||||||
|
# undef RTREE_GET_VALIDATE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define RTREE_LOCK(l)
|
||||||
|
#define RTREE_UNLOCK(l)
|
||||||
|
#ifdef JEMALLOC_DEBUG
|
||||||
|
/*
|
||||||
|
* Suppose that it were possible for a jemalloc-allocated chunk to be
|
||||||
|
* munmap()ped, followed by a different allocator in another thread re-using
|
||||||
|
* overlapping virtual memory, all without invalidating the cached rtree
|
||||||
|
* value. The result would be a false positive (the rtree would claim that
|
||||||
|
* jemalloc owns memory that it had actually discarded). This scenario
|
||||||
|
* seems impossible, but the following assertion is a prudent sanity check.
|
||||||
|
*/
|
||||||
|
# define RTREE_GET_VALIDATE \
|
||||||
|
assert(rtree_get_locked(rtree, key) == ret);
|
||||||
|
#else
|
||||||
|
# define RTREE_GET_VALIDATE
|
||||||
|
#endif
|
||||||
|
RTREE_GET_GENERATE(rtree_get)
|
||||||
|
#undef RTREE_LOCK
|
||||||
|
#undef RTREE_UNLOCK
|
||||||
|
#undef RTREE_GET_VALIDATE
|
||||||
|
|
||||||
|
JEMALLOC_INLINE bool
|
||||||
|
rtree_set(rtree_t *rtree, uintptr_t key, void *val)
|
||||||
|
{
|
||||||
|
uintptr_t subkey;
|
||||||
|
unsigned i, lshift, height, bits;
|
||||||
|
void **node, **child;
|
||||||
|
|
||||||
|
malloc_mutex_lock(&rtree->mutex);
|
||||||
|
for (i = lshift = 0, height = rtree->height, node = rtree->root;
|
||||||
|
i < height - 1;
|
||||||
|
i++, lshift += bits, node = child) {
|
||||||
|
bits = rtree->level2bits[i];
|
||||||
|
subkey = (key << lshift) >> ((ZU(1) << (LG_SIZEOF_PTR+3)) -
|
||||||
|
bits);
|
||||||
|
child = (void**)node[subkey];
|
||||||
|
if (child == NULL) {
|
||||||
|
child = (void**)base_alloc(sizeof(void *) <<
|
||||||
|
rtree->level2bits[i+1]);
|
||||||
|
if (child == NULL) {
|
||||||
|
malloc_mutex_unlock(&rtree->mutex);
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
memset(child, 0, sizeof(void *) <<
|
||||||
|
rtree->level2bits[i+1]);
|
||||||
|
node[subkey] = child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* node is a leaf, so it contains values rather than node pointers. */
|
||||||
|
bits = rtree->level2bits[i];
|
||||||
|
subkey = (key << lshift) >> ((ZU(1) << (LG_SIZEOF_PTR+3)) - bits);
|
||||||
|
node[subkey] = val;
|
||||||
|
malloc_mutex_unlock(&rtree->mutex);
|
||||||
|
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_INLINES */
|
||||||
|
/******************************************************************************/
|
||||||
@@ -31,8 +31,24 @@ struct tcache_bin_stats_s {
|
|||||||
|
|
||||||
struct malloc_bin_stats_s {
|
struct malloc_bin_stats_s {
|
||||||
/*
|
/*
|
||||||
* Number of allocation requests that corresponded to the size of this
|
* Current number of bytes allocated, including objects currently
|
||||||
* bin.
|
* cached by tcache.
|
||||||
|
*/
|
||||||
|
size_t allocated;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Total number of allocation/deallocation requests served directly by
|
||||||
|
* the bin. 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.
|
||||||
|
*/
|
||||||
|
uint64_t nmalloc;
|
||||||
|
uint64_t ndalloc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Number of allocation requests that correspond to the size of this
|
||||||
|
* bin. This includes requests served by tcache, though tcache only
|
||||||
|
* periodically merges into this counter.
|
||||||
*/
|
*/
|
||||||
uint64_t nrequests;
|
uint64_t nrequests;
|
||||||
|
|
||||||
@@ -62,7 +78,18 @@ struct malloc_bin_stats_s {
|
|||||||
|
|
||||||
struct malloc_large_stats_s {
|
struct malloc_large_stats_s {
|
||||||
/*
|
/*
|
||||||
* Number of allocation requests that corresponded to this size class.
|
* 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.
|
||||||
|
*/
|
||||||
|
uint64_t nmalloc;
|
||||||
|
uint64_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;
|
uint64_t nrequests;
|
||||||
|
|
||||||
@@ -87,17 +114,10 @@ struct arena_stats_s {
|
|||||||
uint64_t purged;
|
uint64_t purged;
|
||||||
|
|
||||||
/* Per-size-category statistics. */
|
/* Per-size-category statistics. */
|
||||||
size_t allocated_small;
|
|
||||||
uint64_t nmalloc_small;
|
|
||||||
uint64_t ndalloc_small;
|
|
||||||
|
|
||||||
size_t allocated_medium;
|
|
||||||
uint64_t nmalloc_medium;
|
|
||||||
uint64_t ndalloc_medium;
|
|
||||||
|
|
||||||
size_t allocated_large;
|
size_t allocated_large;
|
||||||
uint64_t nmalloc_large;
|
uint64_t nmalloc_large;
|
||||||
uint64_t ndalloc_large;
|
uint64_t ndalloc_large;
|
||||||
|
uint64_t nrequests_large;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* One element for each possible size class, including sizes that
|
* One element for each possible size class, including sizes that
|
||||||
@@ -134,22 +154,54 @@ struct chunk_stats_s {
|
|||||||
|
|
||||||
extern bool opt_stats_print;
|
extern bool opt_stats_print;
|
||||||
|
|
||||||
char *umax2s(uintmax_t x, unsigned base, char *s);
|
|
||||||
#ifdef JEMALLOC_STATS
|
#ifdef JEMALLOC_STATS
|
||||||
void malloc_cprintf(void (*write4)(void *, const char *, const char *,
|
extern size_t stats_cactive;
|
||||||
const char *, const char *), void *w4opaque, const char *format, ...)
|
#endif
|
||||||
JEMALLOC_ATTR(format(printf, 3, 4));
|
|
||||||
|
char *u2s(uint64_t x, unsigned base, char *s);
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
void malloc_cprintf(void (*write)(void *, const char *), void *cbopaque,
|
||||||
|
const char *format, ...) JEMALLOC_ATTR(format(printf, 3, 4));
|
||||||
void malloc_printf(const char *format, ...)
|
void malloc_printf(const char *format, ...)
|
||||||
JEMALLOC_ATTR(format(printf, 1, 2));
|
JEMALLOC_ATTR(format(printf, 1, 2));
|
||||||
#endif
|
#endif
|
||||||
void stats_print(void (*write4)(void *, const char *, const char *,
|
void stats_print(void (*write)(void *, const char *), void *cbopaque,
|
||||||
const char *, const char *), void *w4opaque, const char *opts);
|
const char *opts);
|
||||||
|
|
||||||
#endif /* JEMALLOC_H_EXTERNS */
|
#endif /* JEMALLOC_H_EXTERNS */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
#ifdef JEMALLOC_STATS
|
|
||||||
#ifdef JEMALLOC_H_INLINES
|
#ifdef JEMALLOC_H_INLINES
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
|
||||||
|
atomic_add_z(&stats_cactive, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE void
|
||||||
|
stats_cactive_sub(size_t size)
|
||||||
|
{
|
||||||
|
|
||||||
|
atomic_sub_z(&stats_cactive, size);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* JEMALLOC_H_INLINES */
|
|
||||||
#endif /* JEMALLOC_STATS */
|
#endif /* JEMALLOC_STATS */
|
||||||
|
#endif /* JEMALLOC_H_INLINES */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
431
include/jemalloc/internal/tcache.h
Normal file
431
include/jemalloc/internal/tcache.h
Normal file
@@ -0,0 +1,431 @@
|
|||||||
|
#ifdef JEMALLOC_TCACHE
|
||||||
|
/******************************************************************************/
|
||||||
|
#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;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 run 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
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (1U << opt_lg_tcache_gc_sweep) is the approximate number of allocation
|
||||||
|
* events between full GC sweeps (-1: disabled). Integer rounding may cause
|
||||||
|
* the actual number to be slightly higher, since GC is performed
|
||||||
|
* incrementally.
|
||||||
|
*/
|
||||||
|
#define LG_TCACHE_GC_SWEEP_DEFAULT 13
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_TYPES */
|
||||||
|
/******************************************************************************/
|
||||||
|
#ifdef JEMALLOC_H_STRUCTS
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 {
|
||||||
|
# ifdef JEMALLOC_STATS
|
||||||
|
tcache_bin_stats_t tstats;
|
||||||
|
# endif
|
||||||
|
int low_water; /* Min # cached since last GC. */
|
||||||
|
unsigned lg_fill_div; /* Fill (ncached_max >> lg_fill_div). */
|
||||||
|
unsigned ncached; /* # of cached objects. */
|
||||||
|
void **avail; /* Stack of available objects. */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tcache_s {
|
||||||
|
# ifdef JEMALLOC_STATS
|
||||||
|
ql_elm(tcache_t) link; /* Used for aggregating stats. */
|
||||||
|
# endif
|
||||||
|
# ifdef JEMALLOC_PROF
|
||||||
|
uint64_t prof_accumbytes;/* Cleared after arena_prof_accum() */
|
||||||
|
# endif
|
||||||
|
arena_t *arena; /* This thread's arena. */
|
||||||
|
unsigned ev_cnt; /* Event count since incremental GC. */
|
||||||
|
unsigned 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.
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_STRUCTS */
|
||||||
|
/******************************************************************************/
|
||||||
|
#ifdef JEMALLOC_H_EXTERNS
|
||||||
|
|
||||||
|
extern bool opt_tcache;
|
||||||
|
extern ssize_t opt_lg_tcache_max;
|
||||||
|
extern ssize_t opt_lg_tcache_gc_sweep;
|
||||||
|
|
||||||
|
extern tcache_bin_info_t *tcache_bin_info;
|
||||||
|
|
||||||
|
/* Map of thread-specific caches. */
|
||||||
|
#ifndef NO_TLS
|
||||||
|
extern __thread tcache_t *tcache_tls
|
||||||
|
JEMALLOC_ATTR(tls_model("initial-exec"));
|
||||||
|
# define TCACHE_GET() tcache_tls
|
||||||
|
# define TCACHE_SET(v) do { \
|
||||||
|
tcache_tls = (tcache_t *)(v); \
|
||||||
|
pthread_setspecific(tcache_tsd, (void *)(v)); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
# define TCACHE_GET() ((tcache_t *)pthread_getspecific(tcache_tsd))
|
||||||
|
# define TCACHE_SET(v) do { \
|
||||||
|
pthread_setspecific(tcache_tsd, (void *)(v)); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
extern pthread_key_t tcache_tsd;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Number of tcache bins. There are nbins small-object bins, plus 0 or more
|
||||||
|
* large-object bins.
|
||||||
|
*/
|
||||||
|
extern size_t nhbins;
|
||||||
|
|
||||||
|
/* Maximum cached size class. */
|
||||||
|
extern size_t tcache_maxclass;
|
||||||
|
|
||||||
|
/* Number of tcache allocation/deallocation events between incremental GCs. */
|
||||||
|
extern unsigned tcache_gc_incr;
|
||||||
|
|
||||||
|
void tcache_bin_flush_small(tcache_bin_t *tbin, size_t binind, unsigned rem
|
||||||
|
#if (defined(JEMALLOC_STATS) || defined(JEMALLOC_PROF))
|
||||||
|
, tcache_t *tcache
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
void tcache_bin_flush_large(tcache_bin_t *tbin, size_t binind, unsigned rem
|
||||||
|
#if (defined(JEMALLOC_STATS) || defined(JEMALLOC_PROF))
|
||||||
|
, tcache_t *tcache
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
tcache_t *tcache_create(arena_t *arena);
|
||||||
|
void *tcache_alloc_small_hard(tcache_t *tcache, tcache_bin_t *tbin,
|
||||||
|
size_t binind);
|
||||||
|
void tcache_destroy(tcache_t *tcache);
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
void tcache_stats_merge(tcache_t *tcache, arena_t *arena);
|
||||||
|
#endif
|
||||||
|
bool tcache_boot(void);
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_EXTERNS */
|
||||||
|
/******************************************************************************/
|
||||||
|
#ifdef JEMALLOC_H_INLINES
|
||||||
|
|
||||||
|
#ifndef JEMALLOC_ENABLE_INLINE
|
||||||
|
void tcache_event(tcache_t *tcache);
|
||||||
|
tcache_t *tcache_get(void);
|
||||||
|
void *tcache_alloc_easy(tcache_bin_t *tbin);
|
||||||
|
void *tcache_alloc_small(tcache_t *tcache, size_t size, bool zero);
|
||||||
|
void *tcache_alloc_large(tcache_t *tcache, size_t size, bool zero);
|
||||||
|
void tcache_dalloc_small(tcache_t *tcache, void *ptr);
|
||||||
|
void tcache_dalloc_large(tcache_t *tcache, void *ptr, size_t size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_TCACHE_C_))
|
||||||
|
JEMALLOC_INLINE tcache_t *
|
||||||
|
tcache_get(void)
|
||||||
|
{
|
||||||
|
tcache_t *tcache;
|
||||||
|
|
||||||
|
if ((isthreaded & opt_tcache) == false)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
tcache = TCACHE_GET();
|
||||||
|
if ((uintptr_t)tcache <= (uintptr_t)2) {
|
||||||
|
if (tcache == NULL) {
|
||||||
|
tcache = tcache_create(choose_arena());
|
||||||
|
if (tcache == NULL)
|
||||||
|
return (NULL);
|
||||||
|
} else {
|
||||||
|
if (tcache == (void *)(uintptr_t)1) {
|
||||||
|
/*
|
||||||
|
* Make a note that an allocator function was
|
||||||
|
* called after the tcache_thread_cleanup() was
|
||||||
|
* called.
|
||||||
|
*/
|
||||||
|
TCACHE_SET((uintptr_t)2);
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (tcache);
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE void
|
||||||
|
tcache_event(tcache_t *tcache)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (tcache_gc_incr == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
tcache->ev_cnt++;
|
||||||
|
assert(tcache->ev_cnt <= tcache_gc_incr);
|
||||||
|
if (tcache->ev_cnt == tcache_gc_incr) {
|
||||||
|
size_t binind = tcache->next_gc_bin;
|
||||||
|
tcache_bin_t *tbin = &tcache->tbins[binind];
|
||||||
|
tcache_bin_info_t *tbin_info = &tcache_bin_info[binind];
|
||||||
|
|
||||||
|
if (tbin->low_water > 0) {
|
||||||
|
/*
|
||||||
|
* Flush (ceiling) 3/4 of the objects below the low
|
||||||
|
* water mark.
|
||||||
|
*/
|
||||||
|
if (binind < nbins) {
|
||||||
|
tcache_bin_flush_small(tbin, binind,
|
||||||
|
tbin->ncached - tbin->low_water +
|
||||||
|
(tbin->low_water >> 2)
|
||||||
|
#if (defined(JEMALLOC_STATS) || defined(JEMALLOC_PROF))
|
||||||
|
, tcache
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
tcache_bin_flush_large(tbin, binind,
|
||||||
|
tbin->ncached - tbin->low_water +
|
||||||
|
(tbin->low_water >> 2)
|
||||||
|
#if (defined(JEMALLOC_STATS) || defined(JEMALLOC_PROF))
|
||||||
|
, tcache
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
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)
|
||||||
|
tcache->next_gc_bin = 0;
|
||||||
|
tcache->ev_cnt = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE void *
|
||||||
|
tcache_alloc_easy(tcache_bin_t *tbin)
|
||||||
|
{
|
||||||
|
void *ret;
|
||||||
|
|
||||||
|
if (tbin->ncached == 0) {
|
||||||
|
tbin->low_water = -1;
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
tbin->ncached--;
|
||||||
|
if ((int)tbin->ncached < tbin->low_water)
|
||||||
|
tbin->low_water = tbin->ncached;
|
||||||
|
ret = tbin->avail[tbin->ncached];
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE void *
|
||||||
|
tcache_alloc_small(tcache_t *tcache, size_t size, bool zero)
|
||||||
|
{
|
||||||
|
void *ret;
|
||||||
|
size_t binind;
|
||||||
|
tcache_bin_t *tbin;
|
||||||
|
|
||||||
|
binind = SMALL_SIZE2BIN(size);
|
||||||
|
assert(binind < nbins);
|
||||||
|
tbin = &tcache->tbins[binind];
|
||||||
|
ret = tcache_alloc_easy(tbin);
|
||||||
|
if (ret == NULL) {
|
||||||
|
ret = tcache_alloc_small_hard(tcache, tbin, binind);
|
||||||
|
if (ret == NULL)
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
assert(arena_salloc(ret) == arena_bin_info[binind].reg_size);
|
||||||
|
|
||||||
|
if (zero == false) {
|
||||||
|
#ifdef JEMALLOC_FILL
|
||||||
|
if (opt_junk)
|
||||||
|
memset(ret, 0xa5, size);
|
||||||
|
else if (opt_zero)
|
||||||
|
memset(ret, 0, size);
|
||||||
|
#endif
|
||||||
|
} else
|
||||||
|
memset(ret, 0, size);
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
tbin->tstats.nrequests++;
|
||||||
|
#endif
|
||||||
|
#ifdef JEMALLOC_PROF
|
||||||
|
tcache->prof_accumbytes += arena_bin_info[binind].reg_size;
|
||||||
|
#endif
|
||||||
|
tcache_event(tcache);
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE void *
|
||||||
|
tcache_alloc_large(tcache_t *tcache, size_t size, bool zero)
|
||||||
|
{
|
||||||
|
void *ret;
|
||||||
|
size_t binind;
|
||||||
|
tcache_bin_t *tbin;
|
||||||
|
|
||||||
|
size = PAGE_CEILING(size);
|
||||||
|
assert(size <= tcache_maxclass);
|
||||||
|
binind = nbins + (size >> PAGE_SHIFT) - 1;
|
||||||
|
assert(binind < nhbins);
|
||||||
|
tbin = &tcache->tbins[binind];
|
||||||
|
ret = tcache_alloc_easy(tbin);
|
||||||
|
if (ret == NULL) {
|
||||||
|
/*
|
||||||
|
* Only allocate one large object at a time, because it's quite
|
||||||
|
* expensive to create one and not use it.
|
||||||
|
*/
|
||||||
|
ret = arena_malloc_large(tcache->arena, size, zero);
|
||||||
|
if (ret == NULL)
|
||||||
|
return (NULL);
|
||||||
|
} else {
|
||||||
|
#ifdef JEMALLOC_PROF
|
||||||
|
arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ret);
|
||||||
|
size_t pageind = (((uintptr_t)ret - (uintptr_t)chunk) >>
|
||||||
|
PAGE_SHIFT);
|
||||||
|
chunk->map[pageind-map_bias].bits &= ~CHUNK_MAP_CLASS_MASK;
|
||||||
|
#endif
|
||||||
|
if (zero == false) {
|
||||||
|
#ifdef JEMALLOC_FILL
|
||||||
|
if (opt_junk)
|
||||||
|
memset(ret, 0xa5, size);
|
||||||
|
else if (opt_zero)
|
||||||
|
memset(ret, 0, size);
|
||||||
|
#endif
|
||||||
|
} else
|
||||||
|
memset(ret, 0, size);
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
tbin->tstats.nrequests++;
|
||||||
|
#endif
|
||||||
|
#ifdef JEMALLOC_PROF
|
||||||
|
tcache->prof_accumbytes += size;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
tcache_event(tcache);
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE void
|
||||||
|
tcache_dalloc_small(tcache_t *tcache, void *ptr)
|
||||||
|
{
|
||||||
|
arena_t *arena;
|
||||||
|
arena_chunk_t *chunk;
|
||||||
|
arena_run_t *run;
|
||||||
|
arena_bin_t *bin;
|
||||||
|
tcache_bin_t *tbin;
|
||||||
|
tcache_bin_info_t *tbin_info;
|
||||||
|
size_t pageind, binind;
|
||||||
|
arena_chunk_map_t *mapelm;
|
||||||
|
|
||||||
|
assert(arena_salloc(ptr) <= small_maxclass);
|
||||||
|
|
||||||
|
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
||||||
|
arena = chunk->arena;
|
||||||
|
pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT;
|
||||||
|
mapelm = &chunk->map[pageind-map_bias];
|
||||||
|
run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)((pageind -
|
||||||
|
(mapelm->bits >> PAGE_SHIFT)) << PAGE_SHIFT));
|
||||||
|
dassert(run->magic == ARENA_RUN_MAGIC);
|
||||||
|
bin = run->bin;
|
||||||
|
binind = ((uintptr_t)bin - (uintptr_t)&arena->bins) /
|
||||||
|
sizeof(arena_bin_t);
|
||||||
|
assert(binind < nbins);
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_FILL
|
||||||
|
if (opt_junk)
|
||||||
|
memset(ptr, 0x5a, arena_bin_info[binind].reg_size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
tbin = &tcache->tbins[binind];
|
||||||
|
tbin_info = &tcache_bin_info[binind];
|
||||||
|
if (tbin->ncached == tbin_info->ncached_max) {
|
||||||
|
tcache_bin_flush_small(tbin, binind, (tbin_info->ncached_max >>
|
||||||
|
1)
|
||||||
|
#if (defined(JEMALLOC_STATS) || defined(JEMALLOC_PROF))
|
||||||
|
, tcache
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
}
|
||||||
|
assert(tbin->ncached < tbin_info->ncached_max);
|
||||||
|
tbin->avail[tbin->ncached] = ptr;
|
||||||
|
tbin->ncached++;
|
||||||
|
|
||||||
|
tcache_event(tcache);
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE void
|
||||||
|
tcache_dalloc_large(tcache_t *tcache, void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
arena_t *arena;
|
||||||
|
arena_chunk_t *chunk;
|
||||||
|
size_t pageind, binind;
|
||||||
|
tcache_bin_t *tbin;
|
||||||
|
tcache_bin_info_t *tbin_info;
|
||||||
|
|
||||||
|
assert((size & PAGE_MASK) == 0);
|
||||||
|
assert(arena_salloc(ptr) > small_maxclass);
|
||||||
|
assert(arena_salloc(ptr) <= tcache_maxclass);
|
||||||
|
|
||||||
|
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
||||||
|
arena = chunk->arena;
|
||||||
|
pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT;
|
||||||
|
binind = nbins + (size >> PAGE_SHIFT) - 1;
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_FILL
|
||||||
|
if (opt_junk)
|
||||||
|
memset(ptr, 0x5a, size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
tbin = &tcache->tbins[binind];
|
||||||
|
tbin_info = &tcache_bin_info[binind];
|
||||||
|
if (tbin->ncached == tbin_info->ncached_max) {
|
||||||
|
tcache_bin_flush_large(tbin, binind, (tbin_info->ncached_max >>
|
||||||
|
1)
|
||||||
|
#if (defined(JEMALLOC_STATS) || defined(JEMALLOC_PROF))
|
||||||
|
, tcache
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
}
|
||||||
|
assert(tbin->ncached < tbin_info->ncached_max);
|
||||||
|
tbin->avail[tbin->ncached] = ptr;
|
||||||
|
tbin->ncached++;
|
||||||
|
|
||||||
|
tcache_event(tcache);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_INLINES */
|
||||||
|
/******************************************************************************/
|
||||||
|
#endif /* JEMALLOC_TCACHE */
|
||||||
23
include/jemalloc/internal/zone.h
Normal file
23
include/jemalloc/internal/zone.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#ifndef JEMALLOC_ZONE
|
||||||
|
# error "This source file is for zones on Darwin (OS X)."
|
||||||
|
#endif
|
||||||
|
/******************************************************************************/
|
||||||
|
#ifdef JEMALLOC_H_TYPES
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_TYPES */
|
||||||
|
/******************************************************************************/
|
||||||
|
#ifdef JEMALLOC_H_STRUCTS
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_STRUCTS */
|
||||||
|
/******************************************************************************/
|
||||||
|
#ifdef JEMALLOC_H_EXTERNS
|
||||||
|
|
||||||
|
malloc_zone_t *create_zone(void);
|
||||||
|
void szone2ozone(malloc_zone_t *zone);
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_EXTERNS */
|
||||||
|
/******************************************************************************/
|
||||||
|
#ifdef JEMALLOC_H_INLINES
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_H_INLINES */
|
||||||
|
/******************************************************************************/
|
||||||
@@ -4,6 +4,9 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <strings.h>
|
||||||
|
|
||||||
#define JEMALLOC_VERSION "@jemalloc_version@"
|
#define JEMALLOC_VERSION "@jemalloc_version@"
|
||||||
#define JEMALLOC_VERSION_MAJOR @jemalloc_version_major@
|
#define JEMALLOC_VERSION_MAJOR @jemalloc_version_major@
|
||||||
#define JEMALLOC_VERSION_MINOR @jemalloc_version_minor@
|
#define JEMALLOC_VERSION_MINOR @jemalloc_version_minor@
|
||||||
@@ -16,9 +19,21 @@ extern "C" {
|
|||||||
# define JEMALLOC_P(s) s
|
# define JEMALLOC_P(s) s
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern const char *JEMALLOC_P(malloc_options);
|
#define ALLOCM_LG_ALIGN(la) (la)
|
||||||
extern void (*JEMALLOC_P(malloc_message))(void *, const char *p1,
|
#if LG_SIZEOF_PTR == 2
|
||||||
const char *p2, const char *p3, const char *p4);
|
#define ALLOCM_ALIGN(a) (ffs(a)-1)
|
||||||
|
#else
|
||||||
|
#define ALLOCM_ALIGN(a) ((a < (size_t)INT_MAX) ? ffs(a)-1 : ffs(a>>32)+31)
|
||||||
|
#endif
|
||||||
|
#define ALLOCM_ZERO ((int)0x40)
|
||||||
|
#define ALLOCM_NO_MOVE ((int)0x80)
|
||||||
|
|
||||||
|
#define ALLOCM_SUCCESS 0
|
||||||
|
#define ALLOCM_ERR_OOM 1
|
||||||
|
#define ALLOCM_ERR_NOT_MOVED 2
|
||||||
|
|
||||||
|
extern const char *JEMALLOC_P(malloc_conf);
|
||||||
|
extern void (*JEMALLOC_P(malloc_message))(void *, const char *);
|
||||||
|
|
||||||
void *JEMALLOC_P(malloc)(size_t size) JEMALLOC_ATTR(malloc);
|
void *JEMALLOC_P(malloc)(size_t size) JEMALLOC_ATTR(malloc);
|
||||||
void *JEMALLOC_P(calloc)(size_t num, size_t size) JEMALLOC_ATTR(malloc);
|
void *JEMALLOC_P(calloc)(size_t num, size_t size) JEMALLOC_ATTR(malloc);
|
||||||
@@ -28,9 +43,8 @@ void *JEMALLOC_P(realloc)(void *ptr, size_t size);
|
|||||||
void JEMALLOC_P(free)(void *ptr);
|
void JEMALLOC_P(free)(void *ptr);
|
||||||
|
|
||||||
size_t JEMALLOC_P(malloc_usable_size)(const void *ptr);
|
size_t JEMALLOC_P(malloc_usable_size)(const void *ptr);
|
||||||
void JEMALLOC_P(malloc_stats_print)(void (*write4)(void *, const char *,
|
void JEMALLOC_P(malloc_stats_print)(void (*write_cb)(void *, const char *),
|
||||||
const char *, const char *, const char *), void *w4opaque,
|
void *cbopaque, const char *opts);
|
||||||
const char *opts);
|
|
||||||
int JEMALLOC_P(mallctl)(const char *name, void *oldp, size_t *oldlenp,
|
int JEMALLOC_P(mallctl)(const char *name, void *oldp, size_t *oldlenp,
|
||||||
void *newp, size_t newlen);
|
void *newp, size_t newlen);
|
||||||
int JEMALLOC_P(mallctlnametomib)(const char *name, size_t *mibp,
|
int JEMALLOC_P(mallctlnametomib)(const char *name, size_t *mibp,
|
||||||
@@ -38,6 +52,14 @@ int JEMALLOC_P(mallctlnametomib)(const char *name, size_t *mibp,
|
|||||||
int JEMALLOC_P(mallctlbymib)(const size_t *mib, size_t miblen, void *oldp,
|
int JEMALLOC_P(mallctlbymib)(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 JEMALLOC_P(allocm)(void **ptr, size_t *rsize, size_t size, int flags)
|
||||||
|
JEMALLOC_ATTR(nonnull(1));
|
||||||
|
int JEMALLOC_P(rallocm)(void **ptr, size_t *rsize, size_t size,
|
||||||
|
size_t extra, int flags) JEMALLOC_ATTR(nonnull(1));
|
||||||
|
int JEMALLOC_P(sallocm)(const void *ptr, size_t *rsize, int flags)
|
||||||
|
JEMALLOC_ATTR(nonnull(1));
|
||||||
|
int JEMALLOC_P(dallocm)(void *ptr, int flags) JEMALLOC_ATTR(nonnull(1));
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
@@ -1,11 +1,6 @@
|
|||||||
#ifndef JEMALLOC_DEFS_H_
|
#ifndef JEMALLOC_DEFS_H_
|
||||||
#define JEMALLOC_DEFS_H_
|
#define JEMALLOC_DEFS_H_
|
||||||
|
|
||||||
/*
|
|
||||||
* jemalloc version string.
|
|
||||||
*/
|
|
||||||
#undef JEMALLOC_VERSION
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If JEMALLOC_PREFIX is defined, it will cause all public APIs to be prefixed.
|
* If JEMALLOC_PREFIX is defined, it will cause all public APIs to be prefixed.
|
||||||
* This makes it possible, with some care, to use multiple allocators
|
* This makes it possible, with some care, to use multiple allocators
|
||||||
@@ -18,16 +13,38 @@
|
|||||||
* the API prefixing.
|
* the API prefixing.
|
||||||
*/
|
*/
|
||||||
#undef JEMALLOC_PREFIX
|
#undef JEMALLOC_PREFIX
|
||||||
|
#undef JEMALLOC_CPREFIX
|
||||||
#if (defined(JEMALLOC_PREFIX) && defined(JEMALLOC_MANGLE))
|
#if (defined(JEMALLOC_PREFIX) && defined(JEMALLOC_MANGLE))
|
||||||
#undef JEMALLOC_P
|
#undef JEMALLOC_P
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* JEMALLOC_PRIVATE_NAMESPACE is used as a prefix for all library-private APIs.
|
||||||
|
* For shared libraries, symbol visibility mechanisms prevent these symbols
|
||||||
|
* from being exported, but for static libraries, naming collisions are a real
|
||||||
|
* possibility.
|
||||||
|
*/
|
||||||
|
#undef JEMALLOC_PRIVATE_NAMESPACE
|
||||||
|
#undef JEMALLOC_N
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hyper-threaded CPUs may need a special instruction inside spin loops in
|
* Hyper-threaded CPUs may need a special instruction inside spin loops in
|
||||||
* order to yield to another virtual CPU.
|
* order to yield to another virtual CPU.
|
||||||
*/
|
*/
|
||||||
#undef CPU_SPINWAIT
|
#undef CPU_SPINWAIT
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Defined if OSAtomic*() functions are available, as provided by Darwin, and
|
||||||
|
* documented in the atomic(3) manual page.
|
||||||
|
*/
|
||||||
|
#undef JEMALLOC_OSATOMIC
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Defined if OSSpin*() functions are available, as provided by Darwin, and
|
||||||
|
* documented in the spinlock(3) manual page.
|
||||||
|
*/
|
||||||
|
#undef JEMALLOC_OSSPIN
|
||||||
|
|
||||||
/* Defined if __attribute__((...)) syntax is supported. */
|
/* Defined if __attribute__((...)) syntax is supported. */
|
||||||
#undef JEMALLOC_HAVE_ATTR
|
#undef JEMALLOC_HAVE_ATTR
|
||||||
#ifdef JEMALLOC_HAVE_ATTR
|
#ifdef JEMALLOC_HAVE_ATTR
|
||||||
@@ -36,6 +53,9 @@
|
|||||||
# define JEMALLOC_ATTR(s)
|
# define JEMALLOC_ATTR(s)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* JEMALLOC_CC_SILENCE enables code that silences unuseful compiler warnings. */
|
||||||
|
#undef JEMALLOC_CC_SILENCE
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* JEMALLOC_DEBUG enables assertions and other sanity checks, and disables
|
* JEMALLOC_DEBUG enables assertions and other sanity checks, and disables
|
||||||
* inline functions.
|
* inline functions.
|
||||||
@@ -54,6 +74,9 @@
|
|||||||
/* Use libgcc for profile backtracing if defined. */
|
/* Use libgcc for profile backtracing if defined. */
|
||||||
#undef JEMALLOC_PROF_LIBGCC
|
#undef JEMALLOC_PROF_LIBGCC
|
||||||
|
|
||||||
|
/* Use gcc intrinsics for profile backtracing if defined. */
|
||||||
|
#undef JEMALLOC_PROF_GCC
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* JEMALLOC_TINY enables support for tiny objects, which are smaller than one
|
* JEMALLOC_TINY enables support for tiny objects, which are smaller than one
|
||||||
* quantum.
|
* quantum.
|
||||||
@@ -61,9 +84,9 @@
|
|||||||
#undef JEMALLOC_TINY
|
#undef JEMALLOC_TINY
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* JEMALLOC_TCACHE enables a thread-specific caching layer for small and medium
|
* JEMALLOC_TCACHE enables a thread-specific caching layer for small objects.
|
||||||
* objects. This makes it possible to allocate/deallocate objects without any
|
* This makes it possible to allocate/deallocate objects without any locking
|
||||||
* locking when the cache is in the steady state.
|
* when the cache is in the steady state.
|
||||||
*/
|
*/
|
||||||
#undef JEMALLOC_TCACHE
|
#undef JEMALLOC_TCACHE
|
||||||
|
|
||||||
@@ -97,10 +120,48 @@
|
|||||||
/* TLS is used to map arenas and magazine caches to threads. */
|
/* TLS is used to map arenas and magazine caches to threads. */
|
||||||
#undef NO_TLS
|
#undef NO_TLS
|
||||||
|
|
||||||
|
/*
|
||||||
|
* JEMALLOC_IVSALLOC enables ivsalloc(), which verifies that pointers reside
|
||||||
|
* within jemalloc-owned chunks before dereferencing them.
|
||||||
|
*/
|
||||||
|
#undef JEMALLOC_IVSALLOC
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Define overrides for non-standard allocator-related functions if they
|
||||||
|
* are present on the system.
|
||||||
|
*/
|
||||||
|
#undef JEMALLOC_OVERRIDE_MEMALIGN
|
||||||
|
#undef JEMALLOC_OVERRIDE_VALLOC
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Darwin (OS X) uses zones to work around Mach-O symbol override shortcomings.
|
||||||
|
*/
|
||||||
|
#undef JEMALLOC_ZONE
|
||||||
|
#undef JEMALLOC_ZONE_VERSION
|
||||||
|
|
||||||
|
/* If defined, use mremap(...MREMAP_FIXED...) for huge realloc(). */
|
||||||
|
#undef JEMALLOC_MREMAP_FIXED
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#undef JEMALLOC_PURGE_MADVISE_DONTNEED
|
||||||
|
#undef JEMALLOC_PURGE_MADVISE_FREE
|
||||||
|
|
||||||
/* sizeof(void *) == 2^LG_SIZEOF_PTR. */
|
/* sizeof(void *) == 2^LG_SIZEOF_PTR. */
|
||||||
#undef LG_SIZEOF_PTR
|
#undef LG_SIZEOF_PTR
|
||||||
|
|
||||||
/* sizeof(int) == 2^LG_SIZEOF_INT. */
|
/* sizeof(int) == 2^LG_SIZEOF_INT. */
|
||||||
#undef LG_SIZEOF_INT
|
#undef LG_SIZEOF_INT
|
||||||
|
|
||||||
|
/* sizeof(long) == 2^LG_SIZEOF_LONG. */
|
||||||
|
#undef LG_SIZEOF_LONG
|
||||||
|
|
||||||
#endif /* JEMALLOC_DEFS_H_ */
|
#endif /* JEMALLOC_DEFS_H_ */
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
# Clear out all vpaths, then set just one (default vpath) for the main build
|
|
||||||
# directory.
|
|
||||||
vpath
|
|
||||||
vpath % .
|
|
||||||
|
|
||||||
# Clear the default suffixes, so that built-in rules are not used.
|
|
||||||
.SUFFIXES :
|
|
||||||
|
|
||||||
SHELL := /bin/sh
|
|
||||||
|
|
||||||
CC := @CC@
|
|
||||||
|
|
||||||
# Configuration parameters.
|
|
||||||
INCLUDEDIR := @INCLUDEDIR@
|
|
||||||
LIBDIR := @LIBDIR@
|
|
||||||
MANDIR := @MANDIR@
|
|
||||||
|
|
||||||
# Build parameters.
|
|
||||||
CPPFLAGS := @CPPFLAGS@ -I@srcroot@include -I@objroot@include
|
|
||||||
CFLAGS := @CFLAGS@ -fPIC -DPIC
|
|
||||||
ifeq (macho, @abi@)
|
|
||||||
CFLAGS += -dynamic
|
|
||||||
endif
|
|
||||||
LDFLAGS := @LDFLAGS@
|
|
||||||
LIBS := @LIBS@
|
|
||||||
RPATH_EXTRA := @RPATH_EXTRA@
|
|
||||||
ifeq (macho, @abi@)
|
|
||||||
SO := dylib
|
|
||||||
else
|
|
||||||
SO := so
|
|
||||||
endif
|
|
||||||
REV := 0
|
|
||||||
|
|
||||||
# Lists of files.
|
|
||||||
CHDRS := @objroot@include/jemalloc@install_suffix@.h \
|
|
||||||
@objroot@include/jemalloc_defs@install_suffix@.h
|
|
||||||
CSRCS := @srcroot@src/jemalloc.c @srcroot@src/arena.c @srcroot@src/base.c \
|
|
||||||
@srcroot@src/chunk.c @srcroot@src/chunk_dss.c \
|
|
||||||
@srcroot@src/chunk_mmap.c @srcroot@src/chunk_swap.c @srcroot@src/ckh.c \
|
|
||||||
@srcroot@src/ctl.c @srcroot@src/extent.c @srcroot@src/hash.c \
|
|
||||||
@srcroot@src/huge.c @srcroot@src/mb.c @srcroot@src/mutex.c \
|
|
||||||
@srcroot@src/prof.c @srcroot@src/stats.c @srcroot@src/tcache.c
|
|
||||||
DSOS := @objroot@lib/libjemalloc@install_suffix@.so.$(REV) \
|
|
||||||
@objroot@lib/libjemalloc@install_suffix@.so \
|
|
||||||
@objroot@lib/libjemalloc@install_suffix@_pic.a
|
|
||||||
MAN3 := @objroot@doc/jemalloc@install_suffix@.3
|
|
||||||
|
|
||||||
.PHONY: all dist install check clean distclean relclean
|
|
||||||
|
|
||||||
# Default target.
|
|
||||||
all: $(DSOS)
|
|
||||||
|
|
||||||
#
|
|
||||||
# Include generated dependency files.
|
|
||||||
#
|
|
||||||
-include $(CSRCS:@srcroot@%.c=@objroot@%.d)
|
|
||||||
|
|
||||||
@objroot@src/%.o: @srcroot@src/%.c
|
|
||||||
@mkdir -p $(@D)
|
|
||||||
$(CC) $(CFLAGS) -c $(CPPFLAGS) -o $@ $<
|
|
||||||
@$(SHELL) -ec "$(CC) -MM $(CPPFLAGS) $< | sed \"s/\($(subst /,\/,$(notdir $(basename $@)))\)\.o\([ :]*\)/$(subst /,\/,$(strip $(dir $@)))\1.o \2/g\" > $(@:%.o=%.d)"
|
|
||||||
|
|
||||||
$(DSOS): $(CSRCS:@srcroot@%.c=@objroot@%.o)
|
|
||||||
@mkdir -p $(@D)
|
|
||||||
$(CC) -shared -o $@ $+ $(LDFLAGS) $(LIBS)
|
|
||||||
ln -sf libjemalloc@install_suffix@.so.$(REV) lib/libjemalloc@install_suffix@.so
|
|
||||||
ar crus @objroot@lib/libjemalloc@install_suffix@_pic.a $+
|
|
||||||
|
|
||||||
install:
|
|
||||||
install -d $(INCLUDEDIR)/jemalloc
|
|
||||||
@for h in $(CHDRS); do \
|
|
||||||
echo "install -m 644 $$h $(INCLUDEDIR)/jemalloc"; \
|
|
||||||
install -m 644 $$h $(INCLUDEDIR)/jemalloc; \
|
|
||||||
done
|
|
||||||
install -d $(LIBDIR)
|
|
||||||
install -m 755 @objroot@lib/libjemalloc@install_suffix@.so.$(REV) $(LIBDIR)
|
|
||||||
ln -sf libjemalloc@install_suffix@.so.$(REV) $(LIBDIR)/libjemalloc@install_suffix@.so
|
|
||||||
install -m 755 @objroot@lib/libjemalloc@install_suffix@_pic.a $(LIBDIR)
|
|
||||||
install -d $(MANDIR)/man3
|
|
||||||
@for m in $(MAN3); do \
|
|
||||||
echo "install -m 644 $$m $(MANDIR)/man3"; \
|
|
||||||
install -m 644 $$m $(MANDIR)/man3; \
|
|
||||||
done
|
|
||||||
|
|
||||||
check:
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f $(CSRCS:@srcroot@%.c=@objroot@%.o)
|
|
||||||
rm -f $(CSRCS:@srcroot@%.c=@objroot@%.d)
|
|
||||||
rm -f $(DSOS)
|
|
||||||
|
|
||||||
distclean: clean
|
|
||||||
rm -f @objroot@config.log
|
|
||||||
rm -f @objroot@config.status
|
|
||||||
rm -f @objroot@cfghdrs.stamp
|
|
||||||
rm -f @objroot@cfgoutputs.stamp
|
|
||||||
rm -f @cfghdrs_out@
|
|
||||||
rm -f @cfgoutputs_out@
|
|
||||||
|
|
||||||
relclean: distclean
|
|
||||||
rm -rf @objroot@autom4te.cache
|
|
||||||
rm -f @objroot@configure
|
|
||||||
rm -f @srcroot@VERSION
|
|
||||||
|
|
||||||
#===============================================================================
|
|
||||||
# Re-configuration rules.
|
|
||||||
|
|
||||||
ifeq (@enable_autogen@, 1)
|
|
||||||
@srcroot@configure : @srcroot@configure.ac
|
|
||||||
cd ./@srcroot@ && @AUTOCONF@
|
|
||||||
|
|
||||||
@objroot@config.status : @srcroot@configure
|
|
||||||
./@objroot@config.status --recheck
|
|
||||||
|
|
||||||
# cfghdrs rules.
|
|
||||||
@srcroot@cfghdrs.stamp.in : @srcroot@configure.ac
|
|
||||||
echo stamp > @srcroot@cfghdrs.stamp.in
|
|
||||||
|
|
||||||
@objroot@cfghdrs.stamp : @cfghdrs_in@ @srcroot@configure
|
|
||||||
./@objroot@config.status
|
|
||||||
@touch $@
|
|
||||||
|
|
||||||
@cfghdrs@ : @objroot@cfghdrs.stamp
|
|
||||||
|
|
||||||
# cfgoutputs rules.
|
|
||||||
@srcroot@cfgoutputs.stamp.in : @srcroot@configure.ac
|
|
||||||
echo stamp > @srcroot@cfgoutputs.stamp.in
|
|
||||||
|
|
||||||
@objroot@cfgoutputs.stamp : @cfgoutputs_in@ @srcroot@configure
|
|
||||||
./@objroot@config.status
|
|
||||||
@touch $@
|
|
||||||
|
|
||||||
# There must be some action in order for make to re-read Makefile when it is
|
|
||||||
# out of date.
|
|
||||||
@cfgoutputs@ : @objroot@cfgoutputs.stamp
|
|
||||||
@true
|
|
||||||
endif
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
jemalloc is a general-purpose scalable concurrent malloc(3) implementation.
|
|
||||||
|
|
||||||
The INSTALL file contains information on how to configure, build, and install
|
|
||||||
jemalloc.
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,487 +0,0 @@
|
|||||||
/******************************************************************************/
|
|
||||||
#ifdef JEMALLOC_H_TYPES
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Subpages are an artificially designated partitioning of pages. Their only
|
|
||||||
* purpose is to support subpage-spaced size classes.
|
|
||||||
*
|
|
||||||
* There must be at least 4 subpages per page, due to the way size classes are
|
|
||||||
* handled.
|
|
||||||
*/
|
|
||||||
#define LG_SUBPAGE 8
|
|
||||||
#define SUBPAGE ((size_t)(1U << LG_SUBPAGE))
|
|
||||||
#define SUBPAGE_MASK (SUBPAGE - 1)
|
|
||||||
|
|
||||||
/* Return the smallest subpage multiple that is >= s. */
|
|
||||||
#define SUBPAGE_CEILING(s) \
|
|
||||||
(((s) + SUBPAGE_MASK) & ~SUBPAGE_MASK)
|
|
||||||
|
|
||||||
#ifdef JEMALLOC_TINY
|
|
||||||
/* Smallest size class to support. */
|
|
||||||
# define LG_TINY_MIN 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Maximum size class that is a multiple of the quantum, but not (necessarily)
|
|
||||||
* a power of 2. Above this size, allocations are rounded up to the nearest
|
|
||||||
* power of 2.
|
|
||||||
*/
|
|
||||||
#define LG_QSPACE_MAX_DEFAULT 7
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Maximum size class that is a multiple of the cacheline, but not (necessarily)
|
|
||||||
* a power of 2. Above this size, allocations are rounded up to the nearest
|
|
||||||
* power of 2.
|
|
||||||
*/
|
|
||||||
#define LG_CSPACE_MAX_DEFAULT 9
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Maximum medium size class. This must not be more than 1/4 of a chunk
|
|
||||||
* (LG_MEDIUM_MAX_DEFAULT <= LG_CHUNK_DEFAULT - 2).
|
|
||||||
*/
|
|
||||||
#define LG_MEDIUM_MAX_DEFAULT 15
|
|
||||||
|
|
||||||
/* Return the smallest medium size class that is >= s. */
|
|
||||||
#define MEDIUM_CEILING(s) \
|
|
||||||
(((s) + mspace_mask) & ~mspace_mask)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Soft limit on the number of medium size classes. Spacing between medium
|
|
||||||
* size classes never exceeds pagesize, which can force more than NBINS_MAX
|
|
||||||
* medium size classes.
|
|
||||||
*/
|
|
||||||
#define NMBINS_MAX 16
|
|
||||||
|
|
||||||
/*
|
|
||||||
* RUN_MAX_OVRHD indicates maximum desired run header overhead. Runs are sized
|
|
||||||
* as small as possible such that this setting is still honored, without
|
|
||||||
* violating other constraints. The goal is to make runs as small as possible
|
|
||||||
* without exceeding a per run external fragmentation threshold.
|
|
||||||
*
|
|
||||||
* We use binary fixed point math for overhead computations, where the binary
|
|
||||||
* point is implicitly RUN_BFP bits to the left.
|
|
||||||
*
|
|
||||||
* Note that it is possible to set RUN_MAX_OVRHD low enough that it cannot be
|
|
||||||
* honored for some/all object sizes, since there is one bit of header overhead
|
|
||||||
* per object (plus a constant). This constraint is relaxed (ignored) for runs
|
|
||||||
* that are so small that the per-region overhead is greater than:
|
|
||||||
*
|
|
||||||
* (RUN_MAX_OVRHD / (reg_size << (3+RUN_BFP))
|
|
||||||
*/
|
|
||||||
#define RUN_BFP 12
|
|
||||||
/* \/ Implicit binary fixed point. */
|
|
||||||
#define RUN_MAX_OVRHD 0x0000003dU
|
|
||||||
#define RUN_MAX_OVRHD_RELAX 0x00001800U
|
|
||||||
|
|
||||||
/* Put a cap on small object run size. This overrides RUN_MAX_OVRHD. */
|
|
||||||
#define RUN_MAX_SMALL \
|
|
||||||
(arena_maxclass <= (1U << (CHUNK_MAP_LG_PG_RANGE + PAGE_SHIFT)) \
|
|
||||||
? arena_maxclass : (1U << (CHUNK_MAP_LG_PG_RANGE + \
|
|
||||||
PAGE_SHIFT)))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The minimum ratio of active:dirty pages per arena is computed as:
|
|
||||||
*
|
|
||||||
* (nactive >> opt_lg_dirty_mult) >= ndirty
|
|
||||||
*
|
|
||||||
* So, supposing that opt_lg_dirty_mult is 5, there can be no less than 32
|
|
||||||
* times as many active pages as dirty pages.
|
|
||||||
*/
|
|
||||||
#define LG_DIRTY_MULT_DEFAULT 5
|
|
||||||
|
|
||||||
typedef struct arena_chunk_map_s arena_chunk_map_t;
|
|
||||||
typedef struct arena_chunk_s arena_chunk_t;
|
|
||||||
typedef struct arena_run_s arena_run_t;
|
|
||||||
typedef struct arena_bin_s arena_bin_t;
|
|
||||||
typedef struct arena_s arena_t;
|
|
||||||
|
|
||||||
#endif /* JEMALLOC_H_TYPES */
|
|
||||||
/******************************************************************************/
|
|
||||||
#ifdef JEMALLOC_H_STRUCTS
|
|
||||||
|
|
||||||
/* Each element of the chunk map corresponds to one page within the chunk. */
|
|
||||||
struct arena_chunk_map_s {
|
|
||||||
/*
|
|
||||||
* Linkage for run trees. There are two disjoint uses:
|
|
||||||
*
|
|
||||||
* 1) arena_t's runs_avail tree.
|
|
||||||
* 2) arena_run_t conceptually uses this linkage for in-use non-full
|
|
||||||
* runs, rather than directly embedding linkage.
|
|
||||||
*/
|
|
||||||
rb_node(arena_chunk_map_t) link;
|
|
||||||
|
|
||||||
#ifdef JEMALLOC_PROF
|
|
||||||
/* Profile counters, used for large object runs. */
|
|
||||||
prof_thr_cnt_t *prof_cnt;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Run address (or size) and various flags are stored together. The bit
|
|
||||||
* layout looks like (assuming 32-bit system):
|
|
||||||
*
|
|
||||||
* ???????? ???????? ????cccc ccccdzla
|
|
||||||
*
|
|
||||||
* ? : Unallocated: Run address for first/last pages, unset for internal
|
|
||||||
* pages.
|
|
||||||
* Small/medium: Don't care.
|
|
||||||
* Large: Run size for first page, unset for trailing pages.
|
|
||||||
* - : Unused.
|
|
||||||
* c : refcount (could overflow for PAGE_SIZE >= 128 KiB)
|
|
||||||
* d : dirty?
|
|
||||||
* z : zeroed?
|
|
||||||
* l : large?
|
|
||||||
* a : allocated?
|
|
||||||
*
|
|
||||||
* Following are example bit patterns for the three types of runs.
|
|
||||||
*
|
|
||||||
* p : run page offset
|
|
||||||
* s : run size
|
|
||||||
* x : don't care
|
|
||||||
* - : 0
|
|
||||||
* [dzla] : bit set
|
|
||||||
*
|
|
||||||
* Unallocated:
|
|
||||||
* ssssssss ssssssss ssss---- --------
|
|
||||||
* xxxxxxxx xxxxxxxx xxxx---- ----d---
|
|
||||||
* ssssssss ssssssss ssss---- -----z--
|
|
||||||
*
|
|
||||||
* Small/medium:
|
|
||||||
* pppppppp ppppcccc cccccccc cccc---a
|
|
||||||
* pppppppp ppppcccc cccccccc cccc---a
|
|
||||||
* pppppppp ppppcccc cccccccc cccc---a
|
|
||||||
*
|
|
||||||
* Large:
|
|
||||||
* ssssssss ssssssss ssss---- ------la
|
|
||||||
* -------- -------- -------- ------la
|
|
||||||
* -------- -------- -------- ------la
|
|
||||||
*/
|
|
||||||
size_t bits;
|
|
||||||
#define CHUNK_MAP_PG_MASK ((size_t)0xfff00000U)
|
|
||||||
#define CHUNK_MAP_PG_SHIFT 20
|
|
||||||
#define CHUNK_MAP_LG_PG_RANGE 12
|
|
||||||
|
|
||||||
#define CHUNK_MAP_RC_MASK ((size_t)0xffff0U)
|
|
||||||
#define CHUNK_MAP_RC_ONE ((size_t)0x00010U)
|
|
||||||
|
|
||||||
#define CHUNK_MAP_FLAGS_MASK ((size_t)0xfU)
|
|
||||||
#define CHUNK_MAP_DIRTY ((size_t)0x8U)
|
|
||||||
#define CHUNK_MAP_ZEROED ((size_t)0x4U)
|
|
||||||
#define CHUNK_MAP_LARGE ((size_t)0x2U)
|
|
||||||
#define CHUNK_MAP_ALLOCATED ((size_t)0x1U)
|
|
||||||
#define CHUNK_MAP_KEY (CHUNK_MAP_DIRTY | CHUNK_MAP_ALLOCATED)
|
|
||||||
};
|
|
||||||
typedef rb_tree(arena_chunk_map_t) arena_avail_tree_t;
|
|
||||||
typedef rb_tree(arena_chunk_map_t) arena_run_tree_t;
|
|
||||||
|
|
||||||
/* Arena chunk header. */
|
|
||||||
struct arena_chunk_s {
|
|
||||||
/* Arena that owns the chunk. */
|
|
||||||
arena_t *arena;
|
|
||||||
|
|
||||||
/* Linkage for the arena's chunks_dirty tree. */
|
|
||||||
rb_node(arena_chunk_t) link_dirty;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* True if the chunk is currently in the chunks_dirty tree, due to
|
|
||||||
* having at some point contained one or more dirty pages. Removal
|
|
||||||
* from chunks_dirty is lazy, so (dirtied && ndirty == 0) is possible.
|
|
||||||
*/
|
|
||||||
bool dirtied;
|
|
||||||
|
|
||||||
/* Number of dirty pages. */
|
|
||||||
size_t ndirty;
|
|
||||||
|
|
||||||
/* Map of pages within chunk that keeps track of free/large/small. */
|
|
||||||
arena_chunk_map_t map[1]; /* Dynamically sized. */
|
|
||||||
};
|
|
||||||
typedef rb_tree(arena_chunk_t) arena_chunk_tree_t;
|
|
||||||
|
|
||||||
struct arena_run_s {
|
|
||||||
#ifdef JEMALLOC_DEBUG
|
|
||||||
uint32_t magic;
|
|
||||||
# define ARENA_RUN_MAGIC 0x384adf93
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Bin this run is associated with. */
|
|
||||||
arena_bin_t *bin;
|
|
||||||
|
|
||||||
/* Index of first element that might have a free region. */
|
|
||||||
unsigned regs_minelm;
|
|
||||||
|
|
||||||
/* Number of free regions in run. */
|
|
||||||
unsigned nfree;
|
|
||||||
|
|
||||||
/* Bitmask of in-use regions (0: in use, 1: free). */
|
|
||||||
unsigned regs_mask[1]; /* Dynamically sized. */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct arena_bin_s {
|
|
||||||
/*
|
|
||||||
* Current run being used to service allocations of this bin's size
|
|
||||||
* class.
|
|
||||||
*/
|
|
||||||
arena_run_t *runcur;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Tree of non-full runs. This tree 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.
|
|
||||||
*/
|
|
||||||
arena_run_tree_t runs;
|
|
||||||
|
|
||||||
/* Size of regions in a run 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 number of regions in a run for this bin's size class. */
|
|
||||||
uint32_t nregs;
|
|
||||||
|
|
||||||
/* Number of elements in a run's regs_mask for this bin's size class. */
|
|
||||||
uint32_t regs_mask_nelms;
|
|
||||||
|
|
||||||
#ifdef JEMALLOC_PROF
|
|
||||||
/*
|
|
||||||
* Offset of first (prof_cnt_t *) in a run header for this bin's size
|
|
||||||
* class, or 0 if (opt_prof == false).
|
|
||||||
*/
|
|
||||||
uint32_t cnt0_offset;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Offset of first region in a run for this bin's size class. */
|
|
||||||
uint32_t reg0_offset;
|
|
||||||
|
|
||||||
#ifdef JEMALLOC_STATS
|
|
||||||
/* Bin statistics. */
|
|
||||||
malloc_bin_stats_t stats;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
struct arena_s {
|
|
||||||
#ifdef JEMALLOC_DEBUG
|
|
||||||
uint32_t magic;
|
|
||||||
# define ARENA_MAGIC 0x947d3d24
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* This arena's index within the arenas array. */
|
|
||||||
unsigned ind;
|
|
||||||
|
|
||||||
/* All operations on this arena require that lock be locked. */
|
|
||||||
malloc_mutex_t lock;
|
|
||||||
|
|
||||||
#ifdef JEMALLOC_STATS
|
|
||||||
arena_stats_t stats;
|
|
||||||
# ifdef JEMALLOC_TCACHE
|
|
||||||
/*
|
|
||||||
* List of tcaches for extant threads associated with this arena.
|
|
||||||
* Stats from these are merged incrementally, and at exit.
|
|
||||||
*/
|
|
||||||
ql_head(tcache_t) tcache_ql;
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef JEMALLOC_PROF
|
|
||||||
uint64_t prof_accumbytes;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Tree of dirty-page-containing chunks this arena manages. */
|
|
||||||
arena_chunk_tree_t chunks_dirty;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
arena_chunk_t *spare;
|
|
||||||
|
|
||||||
/* Number of pages in active runs. */
|
|
||||||
size_t nactive;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Current count of pages within unused runs 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.
|
|
||||||
*/
|
|
||||||
size_t ndirty;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Size/address-ordered tree of this arena's available runs. This tree
|
|
||||||
* is used for first-best-fit run allocation.
|
|
||||||
*/
|
|
||||||
arena_avail_tree_t runs_avail;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* bins is used to store trees of free regions of the following sizes,
|
|
||||||
* assuming a 16-byte quantum, 4 KiB page size, and default
|
|
||||||
* JEMALLOC_OPTIONS.
|
|
||||||
*
|
|
||||||
* bins[i] | size |
|
|
||||||
* --------+--------+
|
|
||||||
* 0 | 2 |
|
|
||||||
* 1 | 4 |
|
|
||||||
* 2 | 8 |
|
|
||||||
* --------+--------+
|
|
||||||
* 3 | 16 |
|
|
||||||
* 4 | 32 |
|
|
||||||
* 5 | 48 |
|
|
||||||
* : :
|
|
||||||
* 8 | 96 |
|
|
||||||
* 9 | 112 |
|
|
||||||
* 10 | 128 |
|
|
||||||
* --------+--------+
|
|
||||||
* 11 | 192 |
|
|
||||||
* 12 | 256 |
|
|
||||||
* 13 | 320 |
|
|
||||||
* 14 | 384 |
|
|
||||||
* 15 | 448 |
|
|
||||||
* 16 | 512 |
|
|
||||||
* --------+--------+
|
|
||||||
* 17 | 768 |
|
|
||||||
* 18 | 1024 |
|
|
||||||
* 19 | 1280 |
|
|
||||||
* : :
|
|
||||||
* 27 | 3328 |
|
|
||||||
* 28 | 3584 |
|
|
||||||
* 29 | 3840 |
|
|
||||||
* --------+--------+
|
|
||||||
* 30 | 4 KiB |
|
|
||||||
* 31 | 6 KiB |
|
|
||||||
* 33 | 8 KiB |
|
|
||||||
* : :
|
|
||||||
* 43 | 28 KiB |
|
|
||||||
* 44 | 30 KiB |
|
|
||||||
* 45 | 32 KiB |
|
|
||||||
* --------+--------+
|
|
||||||
*/
|
|
||||||
arena_bin_t bins[1]; /* Dynamically sized. */
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* JEMALLOC_H_STRUCTS */
|
|
||||||
/******************************************************************************/
|
|
||||||
#ifdef JEMALLOC_H_EXTERNS
|
|
||||||
|
|
||||||
extern size_t opt_lg_qspace_max;
|
|
||||||
extern size_t opt_lg_cspace_max;
|
|
||||||
extern size_t opt_lg_medium_max;
|
|
||||||
extern ssize_t opt_lg_dirty_mult;
|
|
||||||
extern uint8_t const *small_size2bin;
|
|
||||||
|
|
||||||
/* Various bin-related settings. */
|
|
||||||
#ifdef JEMALLOC_TINY /* Number of (2^n)-spaced tiny bins. */
|
|
||||||
# define ntbins ((unsigned)(LG_QUANTUM - LG_TINY_MIN))
|
|
||||||
#else
|
|
||||||
# define ntbins 0
|
|
||||||
#endif
|
|
||||||
extern unsigned nqbins; /* Number of quantum-spaced bins. */
|
|
||||||
extern unsigned ncbins; /* Number of cacheline-spaced bins. */
|
|
||||||
extern unsigned nsbins; /* Number of subpage-spaced bins. */
|
|
||||||
extern unsigned nmbins; /* Number of medium bins. */
|
|
||||||
extern unsigned nbins;
|
|
||||||
extern unsigned mbin0; /* mbin offset (nbins - nmbins). */
|
|
||||||
#ifdef JEMALLOC_TINY
|
|
||||||
# define tspace_max ((size_t)(QUANTUM >> 1))
|
|
||||||
#endif
|
|
||||||
#define qspace_min QUANTUM
|
|
||||||
extern size_t qspace_max;
|
|
||||||
extern size_t cspace_min;
|
|
||||||
extern size_t cspace_max;
|
|
||||||
extern size_t sspace_min;
|
|
||||||
extern size_t sspace_max;
|
|
||||||
#define small_maxclass sspace_max
|
|
||||||
#define medium_min PAGE_SIZE
|
|
||||||
extern size_t medium_max;
|
|
||||||
#define bin_maxclass medium_max
|
|
||||||
|
|
||||||
/* Spacing between medium size classes. */
|
|
||||||
extern size_t lg_mspace;
|
|
||||||
extern size_t mspace_mask;
|
|
||||||
|
|
||||||
#define nlclasses ((chunksize - PAGE_SIZE) >> PAGE_SHIFT)
|
|
||||||
|
|
||||||
#ifdef JEMALLOC_TCACHE
|
|
||||||
void arena_tcache_fill(arena_t *arena, tcache_bin_t *tbin, size_t binind
|
|
||||||
# ifdef JEMALLOC_PROF
|
|
||||||
, uint64_t prof_accumbytes
|
|
||||||
# endif
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
#ifdef JEMALLOC_PROF
|
|
||||||
void arena_prof_accum(arena_t *arena, uint64_t accumbytes);
|
|
||||||
#endif
|
|
||||||
void *arena_malloc_small(arena_t *arena, size_t size, bool zero);
|
|
||||||
void *arena_malloc_medium(arena_t *arena, size_t size, bool zero);
|
|
||||||
void *arena_malloc(size_t size, bool zero);
|
|
||||||
void *arena_palloc(arena_t *arena, size_t alignment, size_t size,
|
|
||||||
size_t alloc_size);
|
|
||||||
size_t arena_salloc(const void *ptr);
|
|
||||||
#ifdef JEMALLOC_PROF
|
|
||||||
prof_thr_cnt_t *arena_prof_cnt_get(const void *ptr);
|
|
||||||
void arena_prof_cnt_set(const void *ptr, prof_thr_cnt_t *cnt);
|
|
||||||
#endif
|
|
||||||
void arena_dalloc_bin(arena_t *arena, arena_chunk_t *chunk, void *ptr,
|
|
||||||
arena_chunk_map_t *mapelm);
|
|
||||||
void arena_dalloc_large(arena_t *arena, arena_chunk_t *chunk, void *ptr);
|
|
||||||
#ifdef JEMALLOC_STATS
|
|
||||||
void arena_stats_merge(arena_t *arena, size_t *nactive, size_t *ndirty,
|
|
||||||
arena_stats_t *astats, malloc_bin_stats_t *bstats,
|
|
||||||
malloc_large_stats_t *lstats);
|
|
||||||
#endif
|
|
||||||
void *arena_ralloc(void *ptr, size_t size, size_t oldsize);
|
|
||||||
bool arena_new(arena_t *arena, unsigned ind);
|
|
||||||
bool arena_boot(void);
|
|
||||||
|
|
||||||
#endif /* JEMALLOC_H_EXTERNS */
|
|
||||||
/******************************************************************************/
|
|
||||||
#ifdef JEMALLOC_H_INLINES
|
|
||||||
|
|
||||||
#ifndef JEMALLOC_ENABLE_INLINE
|
|
||||||
void arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_))
|
|
||||||
JEMALLOC_INLINE void
|
|
||||||
arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr)
|
|
||||||
{
|
|
||||||
size_t pageind;
|
|
||||||
arena_chunk_map_t *mapelm;
|
|
||||||
|
|
||||||
assert(arena != NULL);
|
|
||||||
assert(arena->magic == ARENA_MAGIC);
|
|
||||||
assert(chunk->arena == arena);
|
|
||||||
assert(ptr != NULL);
|
|
||||||
assert(CHUNK_ADDR2BASE(ptr) != ptr);
|
|
||||||
|
|
||||||
pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT);
|
|
||||||
mapelm = &chunk->map[pageind];
|
|
||||||
assert((mapelm->bits & CHUNK_MAP_ALLOCATED) != 0);
|
|
||||||
if ((mapelm->bits & CHUNK_MAP_LARGE) == 0) {
|
|
||||||
/* Small allocation. */
|
|
||||||
#ifdef JEMALLOC_TCACHE
|
|
||||||
tcache_t *tcache;
|
|
||||||
|
|
||||||
if ((tcache = tcache_get()) != NULL)
|
|
||||||
tcache_dalloc(tcache, ptr);
|
|
||||||
else {
|
|
||||||
#endif
|
|
||||||
malloc_mutex_lock(&arena->lock);
|
|
||||||
arena_dalloc_bin(arena, chunk, ptr, mapelm);
|
|
||||||
malloc_mutex_unlock(&arena->lock);
|
|
||||||
#ifdef JEMALLOC_TCACHE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} else
|
|
||||||
arena_dalloc_large(arena, chunk, ptr);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* JEMALLOC_H_INLINES */
|
|
||||||
/******************************************************************************/
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
#ifdef JEMALLOC_PROF
|
|
||||||
/******************************************************************************/
|
|
||||||
#ifdef JEMALLOC_H_TYPES
|
|
||||||
|
|
||||||
typedef struct prof_bt_s prof_bt_t;
|
|
||||||
typedef struct prof_cnt_s prof_cnt_t;
|
|
||||||
typedef struct prof_thr_cnt_s prof_thr_cnt_t;
|
|
||||||
typedef struct prof_ctx_s prof_ctx_t;
|
|
||||||
typedef struct prof_s prof_t;
|
|
||||||
|
|
||||||
/* Option defaults. */
|
|
||||||
#define LG_PROF_BT_MAX_DEFAULT 2
|
|
||||||
#define LG_PROF_SAMPLE_DEFAULT 0
|
|
||||||
#define LG_PROF_INTERVAL_DEFAULT 30
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Hard limit on stack backtrace depth. Note that the version of
|
|
||||||
* prof_backtrace() that is based on __builtin_return_address() necessarily has
|
|
||||||
* a hard-coded number of backtrace frame handlers, so increasing
|
|
||||||
* LG_PROF_BT_MAX requires changing prof_backtrace().
|
|
||||||
*/
|
|
||||||
#define LG_PROF_BT_MAX 7 /* >= LG_PROF_BT_MAX_DEFAULT */
|
|
||||||
#define PROF_BT_MAX (1U << LG_PROF_BT_MAX)
|
|
||||||
|
|
||||||
/* Initial hash table size. */
|
|
||||||
#define PROF_CKH_MINITEMS 64
|
|
||||||
|
|
||||||
/* Size of memory buffer to use when writing dump files. */
|
|
||||||
#define PROF_DUMP_BUF_SIZE 65536
|
|
||||||
|
|
||||||
#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 nignore;
|
|
||||||
unsigned max;
|
|
||||||
} prof_unwind_data_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct prof_cnt_s {
|
|
||||||
/*
|
|
||||||
* Profiling counters. An allocation/deallocation pair can operate on
|
|
||||||
* different prof_thr_cnt_t objects that are linked into the same
|
|
||||||
* prof_ctx_t sets_ql, so it is possible for the cur* counters to go
|
|
||||||
* negative. In principle it is possible for the *bytes counters to
|
|
||||||
* overflow/underflow, but a general solution would require some form
|
|
||||||
* of 128-bit counter solution; this implementation doesn't bother to
|
|
||||||
* solve that problem.
|
|
||||||
*/
|
|
||||||
int64_t curobjs;
|
|
||||||
int64_t curbytes;
|
|
||||||
uint64_t accumobjs;
|
|
||||||
uint64_t accumbytes;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct prof_thr_cnt_s {
|
|
||||||
/* Linkage into prof_ctx_t's sets_ql. */
|
|
||||||
ql_elm(prof_thr_cnt_t) link;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Associated context. If a thread frees an object that it did not
|
|
||||||
* allocate, it is possible that the context is not cached in the
|
|
||||||
* thread's hash table, in which case it must be able to look up the
|
|
||||||
* context, insert a new prof_thr_cnt_t into the thread's hash table,
|
|
||||||
* and link it into the prof_ctx_t's sets_ql.
|
|
||||||
*/
|
|
||||||
prof_ctx_t *ctx;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Threads use memory barriers to update the counters. Since there is
|
|
||||||
* only ever one writer, the only challenge is for the reader to get a
|
|
||||||
* consistent read of the counters.
|
|
||||||
*
|
|
||||||
* The writer uses this series of operations:
|
|
||||||
*
|
|
||||||
* 1) Increment epoch to an odd number.
|
|
||||||
* 2) Update counters.
|
|
||||||
* 3) Increment epoch to an even number.
|
|
||||||
*
|
|
||||||
* The reader must assure 1) that the epoch is even while it reads the
|
|
||||||
* counters, and 2) that the epoch doesn't change between the time it
|
|
||||||
* starts and finishes reading the counters.
|
|
||||||
*/
|
|
||||||
unsigned epoch;
|
|
||||||
|
|
||||||
/* Profiling counters. */
|
|
||||||
prof_cnt_t cnts;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct prof_ctx_s {
|
|
||||||
/* Protects cnt_merged and sets_ql. */
|
|
||||||
malloc_mutex_t lock;
|
|
||||||
|
|
||||||
/* Temporary storage for aggregation during dump. */
|
|
||||||
prof_cnt_t cnt_dump;
|
|
||||||
|
|
||||||
/* When threads exit, they merge their stats into cnt_merged. */
|
|
||||||
prof_cnt_t cnt_merged;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* List of profile counters, one for each thread that has allocated in
|
|
||||||
* this context.
|
|
||||||
*/
|
|
||||||
ql_head(prof_thr_cnt_t) cnts_ql;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* JEMALLOC_H_STRUCTS */
|
|
||||||
/******************************************************************************/
|
|
||||||
#ifdef JEMALLOC_H_EXTERNS
|
|
||||||
|
|
||||||
extern bool opt_prof;
|
|
||||||
extern size_t opt_lg_prof_bt_max; /* Maximum backtrace depth. */
|
|
||||||
extern size_t opt_lg_prof_sample; /* Mean bytes between samples. */
|
|
||||||
extern size_t opt_lg_prof_interval; /* lg(prof_interval). */
|
|
||||||
extern bool opt_prof_udump; /* High-water memory dumping. */
|
|
||||||
extern bool opt_prof_leak; /* Dump leak summary at exit. */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
bool prof_init(prof_t *prof, bool master);
|
|
||||||
void prof_destroy(prof_t *prof);
|
|
||||||
|
|
||||||
prof_thr_cnt_t *prof_alloc_prep(size_t size);
|
|
||||||
prof_thr_cnt_t *prof_cnt_get(const void *ptr);
|
|
||||||
void prof_malloc(const void *ptr, prof_thr_cnt_t *cnt);
|
|
||||||
void prof_realloc(const void *ptr, prof_thr_cnt_t *cnt, const void *old_ptr,
|
|
||||||
size_t old_size, prof_thr_cnt_t *old_cnt);
|
|
||||||
void prof_free(const void *ptr);
|
|
||||||
void prof_idump(void);
|
|
||||||
bool prof_mdump(const char *filename);
|
|
||||||
void prof_udump(void);
|
|
||||||
void prof_boot0(void);
|
|
||||||
bool prof_boot1(void);
|
|
||||||
|
|
||||||
#endif /* JEMALLOC_H_EXTERNS */
|
|
||||||
/******************************************************************************/
|
|
||||||
#ifdef JEMALLOC_H_INLINES
|
|
||||||
|
|
||||||
#endif /* JEMALLOC_H_INLINES */
|
|
||||||
/******************************************************************************/
|
|
||||||
#endif /* JEMALLOC_PROF */
|
|
||||||
@@ -1,286 +0,0 @@
|
|||||||
#ifdef JEMALLOC_TCACHE
|
|
||||||
/******************************************************************************/
|
|
||||||
#ifdef JEMALLOC_H_TYPES
|
|
||||||
|
|
||||||
typedef struct tcache_bin_s tcache_bin_t;
|
|
||||||
typedef struct tcache_s tcache_t;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Default number of cache slots for each bin in the thread cache (0:
|
|
||||||
* disabled).
|
|
||||||
*/
|
|
||||||
#define LG_TCACHE_NSLOTS_DEFAULT 7
|
|
||||||
/*
|
|
||||||
* (1U << opt_lg_tcache_gc_sweep) is the approximate number of allocation
|
|
||||||
* events between full GC sweeps (-1: disabled). Integer rounding may cause
|
|
||||||
* the actual number to be slightly higher, since GC is performed
|
|
||||||
* incrementally.
|
|
||||||
*/
|
|
||||||
#define LG_TCACHE_GC_SWEEP_DEFAULT 13
|
|
||||||
|
|
||||||
#endif /* JEMALLOC_H_TYPES */
|
|
||||||
/******************************************************************************/
|
|
||||||
#ifdef JEMALLOC_H_STRUCTS
|
|
||||||
|
|
||||||
struct tcache_bin_s {
|
|
||||||
# ifdef JEMALLOC_STATS
|
|
||||||
tcache_bin_stats_t tstats;
|
|
||||||
# endif
|
|
||||||
unsigned low_water; /* Min # cached since last GC. */
|
|
||||||
unsigned high_water; /* Max # cached since last GC. */
|
|
||||||
unsigned ncached; /* # of cached objects. */
|
|
||||||
void *slots[1]; /* Dynamically sized. */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct tcache_s {
|
|
||||||
# ifdef JEMALLOC_STATS
|
|
||||||
ql_elm(tcache_t) link; /* Used for aggregating stats. */
|
|
||||||
# endif
|
|
||||||
# ifdef JEMALLOC_PROF
|
|
||||||
uint64_t prof_accumbytes;/* Cleared after arena_prof_accum() */
|
|
||||||
# endif
|
|
||||||
arena_t *arena; /* This thread's arena. */
|
|
||||||
unsigned ev_cnt; /* Event count since incremental GC. */
|
|
||||||
unsigned next_gc_bin; /* Next bin to GC. */
|
|
||||||
tcache_bin_t *tbins[1]; /* Dynamically sized. */
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* JEMALLOC_H_STRUCTS */
|
|
||||||
/******************************************************************************/
|
|
||||||
#ifdef JEMALLOC_H_EXTERNS
|
|
||||||
|
|
||||||
extern size_t opt_lg_tcache_nslots;
|
|
||||||
extern ssize_t opt_lg_tcache_gc_sweep;
|
|
||||||
|
|
||||||
/* Map of thread-specific caches. */
|
|
||||||
extern __thread tcache_t *tcache_tls
|
|
||||||
JEMALLOC_ATTR(tls_model("initial-exec"));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Number of cache slots for each bin in the thread cache, or 0 if tcache is
|
|
||||||
* disabled.
|
|
||||||
*/
|
|
||||||
extern size_t tcache_nslots;
|
|
||||||
|
|
||||||
/* Number of tcache allocation/deallocation events between incremental GCs. */
|
|
||||||
extern unsigned tcache_gc_incr;
|
|
||||||
|
|
||||||
void tcache_bin_flush(tcache_bin_t *tbin, size_t binind, unsigned rem
|
|
||||||
#ifdef JEMALLOC_PROF
|
|
||||||
, tcache_t *tcache
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
tcache_t *tcache_create(arena_t *arena);
|
|
||||||
void tcache_bin_destroy(tcache_t *tcache, tcache_bin_t *tbin,
|
|
||||||
unsigned binind);
|
|
||||||
void *tcache_alloc_hard(tcache_t *tcache, tcache_bin_t *tbin, size_t binind);
|
|
||||||
tcache_bin_t *tcache_bin_create(arena_t *arena);
|
|
||||||
void tcache_destroy(tcache_t *tcache);
|
|
||||||
#ifdef JEMALLOC_STATS
|
|
||||||
void tcache_stats_merge(tcache_t *tcache, arena_t *arena);
|
|
||||||
#endif
|
|
||||||
void tcache_boot(void);
|
|
||||||
|
|
||||||
#endif /* JEMALLOC_H_EXTERNS */
|
|
||||||
/******************************************************************************/
|
|
||||||
#ifdef JEMALLOC_H_INLINES
|
|
||||||
|
|
||||||
#ifndef JEMALLOC_ENABLE_INLINE
|
|
||||||
void tcache_event(tcache_t *tcache);
|
|
||||||
tcache_t *tcache_get(void);
|
|
||||||
void *tcache_bin_alloc(tcache_bin_t *tbin);
|
|
||||||
void *tcache_alloc(tcache_t *tcache, size_t size, bool zero);
|
|
||||||
void tcache_dalloc(tcache_t *tcache, void *ptr);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_TCACHE_C_))
|
|
||||||
JEMALLOC_INLINE tcache_t *
|
|
||||||
tcache_get(void)
|
|
||||||
{
|
|
||||||
tcache_t *tcache;
|
|
||||||
|
|
||||||
if (isthreaded == false || tcache_nslots == 0)
|
|
||||||
return (NULL);
|
|
||||||
|
|
||||||
tcache = tcache_tls;
|
|
||||||
if ((uintptr_t)tcache <= (uintptr_t)1) {
|
|
||||||
if (tcache == NULL) {
|
|
||||||
tcache = tcache_create(choose_arena());
|
|
||||||
if (tcache == NULL)
|
|
||||||
return (NULL);
|
|
||||||
} else
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (tcache);
|
|
||||||
}
|
|
||||||
|
|
||||||
JEMALLOC_INLINE void
|
|
||||||
tcache_event(tcache_t *tcache)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (tcache_gc_incr == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
tcache->ev_cnt++;
|
|
||||||
assert(tcache->ev_cnt <= tcache_gc_incr);
|
|
||||||
if (tcache->ev_cnt >= tcache_gc_incr) {
|
|
||||||
size_t binind = tcache->next_gc_bin;
|
|
||||||
tcache_bin_t *tbin = tcache->tbins[binind];
|
|
||||||
|
|
||||||
if (tbin != NULL) {
|
|
||||||
if (tbin->high_water == 0) {
|
|
||||||
/*
|
|
||||||
* This bin went completely unused for an
|
|
||||||
* entire GC cycle, so throw away the tbin.
|
|
||||||
*/
|
|
||||||
assert(tbin->ncached == 0);
|
|
||||||
tcache_bin_destroy(tcache, tbin, binind);
|
|
||||||
tcache->tbins[binind] = NULL;
|
|
||||||
} else {
|
|
||||||
if (tbin->low_water > 0) {
|
|
||||||
/*
|
|
||||||
* Flush (ceiling) half of the objects
|
|
||||||
* below the low water mark.
|
|
||||||
*/
|
|
||||||
tcache_bin_flush(tbin, binind,
|
|
||||||
tbin->ncached - (tbin->low_water >>
|
|
||||||
1) - (tbin->low_water & 1)
|
|
||||||
#ifdef JEMALLOC_PROF
|
|
||||||
, tcache
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
}
|
|
||||||
tbin->low_water = tbin->ncached;
|
|
||||||
tbin->high_water = tbin->ncached;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tcache->next_gc_bin++;
|
|
||||||
if (tcache->next_gc_bin == nbins)
|
|
||||||
tcache->next_gc_bin = 0;
|
|
||||||
tcache->ev_cnt = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JEMALLOC_INLINE void *
|
|
||||||
tcache_bin_alloc(tcache_bin_t *tbin)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (tbin->ncached == 0)
|
|
||||||
return (NULL);
|
|
||||||
tbin->ncached--;
|
|
||||||
if (tbin->ncached < tbin->low_water)
|
|
||||||
tbin->low_water = tbin->ncached;
|
|
||||||
return (tbin->slots[tbin->ncached]);
|
|
||||||
}
|
|
||||||
|
|
||||||
JEMALLOC_INLINE void *
|
|
||||||
tcache_alloc(tcache_t *tcache, size_t size, bool zero)
|
|
||||||
{
|
|
||||||
void *ret;
|
|
||||||
tcache_bin_t *tbin;
|
|
||||||
size_t binind;
|
|
||||||
|
|
||||||
if (size <= small_maxclass)
|
|
||||||
binind = small_size2bin[size];
|
|
||||||
else {
|
|
||||||
binind = mbin0 + ((MEDIUM_CEILING(size) - medium_min) >>
|
|
||||||
lg_mspace);
|
|
||||||
}
|
|
||||||
assert(binind < nbins);
|
|
||||||
tbin = tcache->tbins[binind];
|
|
||||||
if (tbin == NULL) {
|
|
||||||
tbin = tcache_bin_create(tcache->arena);
|
|
||||||
if (tbin == NULL)
|
|
||||||
return (NULL);
|
|
||||||
tcache->tbins[binind] = tbin;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = tcache_bin_alloc(tbin);
|
|
||||||
if (ret == NULL) {
|
|
||||||
ret = tcache_alloc_hard(tcache, tbin, binind);
|
|
||||||
if (ret == NULL)
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zero == false) {
|
|
||||||
#ifdef JEMALLOC_FILL
|
|
||||||
if (opt_junk)
|
|
||||||
memset(ret, 0xa5, size);
|
|
||||||
else if (opt_zero)
|
|
||||||
memset(ret, 0, size);
|
|
||||||
#endif
|
|
||||||
} else
|
|
||||||
memset(ret, 0, size);
|
|
||||||
|
|
||||||
#ifdef JEMALLOC_STATS
|
|
||||||
tbin->tstats.nrequests++;
|
|
||||||
#endif
|
|
||||||
#ifdef JEMALLOC_PROF
|
|
||||||
tcache->prof_accumbytes += tcache->arena->bins[binind].reg_size;
|
|
||||||
#endif
|
|
||||||
tcache_event(tcache);
|
|
||||||
return (ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
JEMALLOC_INLINE void
|
|
||||||
tcache_dalloc(tcache_t *tcache, void *ptr)
|
|
||||||
{
|
|
||||||
arena_t *arena;
|
|
||||||
arena_chunk_t *chunk;
|
|
||||||
arena_run_t *run;
|
|
||||||
arena_bin_t *bin;
|
|
||||||
tcache_bin_t *tbin;
|
|
||||||
size_t pageind, binind;
|
|
||||||
arena_chunk_map_t *mapelm;
|
|
||||||
|
|
||||||
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
|
||||||
arena = chunk->arena;
|
|
||||||
pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT);
|
|
||||||
mapelm = &chunk->map[pageind];
|
|
||||||
run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)((pageind -
|
|
||||||
((mapelm->bits & CHUNK_MAP_PG_MASK) >> CHUNK_MAP_PG_SHIFT)) <<
|
|
||||||
PAGE_SHIFT));
|
|
||||||
assert(run->magic == ARENA_RUN_MAGIC);
|
|
||||||
bin = run->bin;
|
|
||||||
binind = ((uintptr_t)bin - (uintptr_t)&arena->bins) /
|
|
||||||
sizeof(arena_bin_t);
|
|
||||||
assert(binind < nbins);
|
|
||||||
|
|
||||||
#ifdef JEMALLOC_FILL
|
|
||||||
if (opt_junk)
|
|
||||||
memset(ptr, 0x5a, arena->bins[binind].reg_size);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
tbin = tcache->tbins[binind];
|
|
||||||
if (tbin == NULL) {
|
|
||||||
tbin = tcache_bin_create(choose_arena());
|
|
||||||
if (tbin == NULL) {
|
|
||||||
malloc_mutex_lock(&arena->lock);
|
|
||||||
arena_dalloc_bin(arena, chunk, ptr, mapelm);
|
|
||||||
malloc_mutex_unlock(&arena->lock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
tcache->tbins[binind] = tbin;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tbin->ncached == tcache_nslots)
|
|
||||||
tcache_bin_flush(tbin, binind, (tcache_nslots >> 1)
|
|
||||||
#ifdef JEMALLOC_PROF
|
|
||||||
, tcache
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
assert(tbin->ncached < tcache_nslots);
|
|
||||||
tbin->slots[tbin->ncached] = ptr;
|
|
||||||
tbin->ncached++;
|
|
||||||
if (tbin->ncached > tbin->high_water)
|
|
||||||
tbin->high_water = tbin->ncached;
|
|
||||||
|
|
||||||
tcache_event(tcache);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* JEMALLOC_H_INLINES */
|
|
||||||
/******************************************************************************/
|
|
||||||
#endif /* JEMALLOC_TCACHE */
|
|
||||||
2348
jemalloc/src/arena.c
2348
jemalloc/src/arena.c
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,672 +0,0 @@
|
|||||||
#define JEMALLOC_STATS_C_
|
|
||||||
#include "jemalloc/internal/jemalloc_internal.h"
|
|
||||||
|
|
||||||
#define CTL_GET(n, v, t) do { \
|
|
||||||
size_t sz = sizeof(t); \
|
|
||||||
xmallctl(n, v, &sz, NULL, 0); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define CTL_I_GET(n, v, t) do { \
|
|
||||||
size_t mib[6]; \
|
|
||||||
size_t miblen = sizeof(mib) / sizeof(size_t); \
|
|
||||||
size_t sz = sizeof(t); \
|
|
||||||
xmallctlnametomib(n, mib, &miblen); \
|
|
||||||
mib[2] = i; \
|
|
||||||
xmallctlbymib(mib, miblen, v, &sz, NULL, 0); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define CTL_J_GET(n, v, t) do { \
|
|
||||||
size_t mib[6]; \
|
|
||||||
size_t miblen = sizeof(mib) / sizeof(size_t); \
|
|
||||||
size_t sz = sizeof(t); \
|
|
||||||
xmallctlnametomib(n, mib, &miblen); \
|
|
||||||
mib[2] = j; \
|
|
||||||
xmallctlbymib(mib, miblen, v, &sz, NULL, 0); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define CTL_IJ_GET(n, v, t) do { \
|
|
||||||
size_t mib[6]; \
|
|
||||||
size_t miblen = sizeof(mib) / sizeof(size_t); \
|
|
||||||
size_t sz = sizeof(t); \
|
|
||||||
xmallctlnametomib(n, mib, &miblen); \
|
|
||||||
mib[2] = i; \
|
|
||||||
mib[4] = j; \
|
|
||||||
xmallctlbymib(mib, miblen, v, &sz, NULL, 0); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
/* Data. */
|
|
||||||
|
|
||||||
bool opt_stats_print = false;
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
/* Function prototypes for non-inline static functions. */
|
|
||||||
|
|
||||||
#ifdef JEMALLOC_STATS
|
|
||||||
static void malloc_vcprintf(void (*write4)(void *, const char *,
|
|
||||||
const char *, const char *, const char *), void *w4opaque,
|
|
||||||
const char *format, va_list ap);
|
|
||||||
static void stats_arena_bins_print(void (*write4)(void *, const char *,
|
|
||||||
const char *, const char *, const char *), void *w4opaque, unsigned i);
|
|
||||||
static void stats_arena_lruns_print(void (*write4)(void *, const char *,
|
|
||||||
const char *, const char *, const char *), void *w4opaque, unsigned i);
|
|
||||||
static void stats_arena_print(void (*write4)(void *, const char *,
|
|
||||||
const char *, const char *, const char *), void *w4opaque, unsigned i);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We don't want to depend on vsnprintf() for production builds, since that can
|
|
||||||
* cause unnecessary bloat for static binaries. umax2s() provides minimal
|
|
||||||
* integer printing functionality, so that malloc_printf() use can be limited to
|
|
||||||
* JEMALLOC_STATS code.
|
|
||||||
*/
|
|
||||||
char *
|
|
||||||
umax2s(uintmax_t x, unsigned base, char *s)
|
|
||||||
{
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
i = UMAX2S_BUFSIZE - 1;
|
|
||||||
s[i] = '\0';
|
|
||||||
switch (base) {
|
|
||||||
case 10:
|
|
||||||
do {
|
|
||||||
i--;
|
|
||||||
s[i] = "0123456789"[x % 10];
|
|
||||||
x /= 10;
|
|
||||||
} while (x > 0);
|
|
||||||
break;
|
|
||||||
case 16:
|
|
||||||
do {
|
|
||||||
i--;
|
|
||||||
s[i] = "0123456789abcdef"[x & 0xf];
|
|
||||||
x >>= 4;
|
|
||||||
} while (x > 0);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
do {
|
|
||||||
i--;
|
|
||||||
s[i] = "0123456789abcdefghijklmnopqrstuvwxyz"[x % base];
|
|
||||||
x /= base;
|
|
||||||
} while (x > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (&s[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef JEMALLOC_STATS
|
|
||||||
static void
|
|
||||||
malloc_vcprintf(void (*write4)(void *, const char *, const char *, const char *,
|
|
||||||
const char *), void *w4opaque, const char *format, va_list ap)
|
|
||||||
{
|
|
||||||
char buf[4096];
|
|
||||||
|
|
||||||
if (write4 == NULL) {
|
|
||||||
/*
|
|
||||||
* The caller did not provide an alternate write4 callback
|
|
||||||
* function, so use the default one. malloc_write4() is an
|
|
||||||
* inline function, so use malloc_message() directly here.
|
|
||||||
*/
|
|
||||||
write4 = JEMALLOC_P(malloc_message);
|
|
||||||
w4opaque = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
vsnprintf(buf, sizeof(buf), format, ap);
|
|
||||||
write4(w4opaque, buf, "", "", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Print to a callback function in such a way as to (hopefully) avoid memory
|
|
||||||
* allocation.
|
|
||||||
*/
|
|
||||||
JEMALLOC_ATTR(format(printf, 3, 4))
|
|
||||||
void
|
|
||||||
malloc_cprintf(void (*write4)(void *, const char *, const char *, const char *,
|
|
||||||
const char *), void *w4opaque, const char *format, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, format);
|
|
||||||
malloc_vcprintf(write4, w4opaque, format, ap);
|
|
||||||
va_end(ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Print to stderr in such a way as to (hopefully) avoid memory allocation.
|
|
||||||
*/
|
|
||||||
JEMALLOC_ATTR(format(printf, 1, 2))
|
|
||||||
void
|
|
||||||
malloc_printf(const char *format, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, format);
|
|
||||||
malloc_vcprintf(NULL, NULL, format, ap);
|
|
||||||
va_end(ap);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef JEMALLOC_STATS
|
|
||||||
static void
|
|
||||||
stats_arena_bins_print(void (*write4)(void *, const char *, const char *,
|
|
||||||
const char *, const char *), void *w4opaque, unsigned i)
|
|
||||||
{
|
|
||||||
size_t pagesize;
|
|
||||||
bool config_tcache;
|
|
||||||
unsigned nbins, j, gap_start;
|
|
||||||
|
|
||||||
CTL_GET("arenas.pagesize", &pagesize, size_t);
|
|
||||||
|
|
||||||
CTL_GET("config.tcache", &config_tcache, bool);
|
|
||||||
if (config_tcache) {
|
|
||||||
malloc_cprintf(write4, w4opaque,
|
|
||||||
"bins: bin size regs pgs nrequests "
|
|
||||||
"nfills nflushes newruns reruns maxruns curruns\n");
|
|
||||||
} else {
|
|
||||||
malloc_cprintf(write4, w4opaque,
|
|
||||||
"bins: bin size regs pgs nrequests "
|
|
||||||
"newruns reruns maxruns curruns\n");
|
|
||||||
}
|
|
||||||
CTL_GET("arenas.nbins", &nbins, unsigned);
|
|
||||||
for (j = 0, gap_start = UINT_MAX; j < nbins; j++) {
|
|
||||||
uint64_t nruns;
|
|
||||||
|
|
||||||
CTL_IJ_GET("stats.arenas.0.bins.0.nruns", &nruns, uint64_t);
|
|
||||||
if (nruns == 0) {
|
|
||||||
if (gap_start == UINT_MAX)
|
|
||||||
gap_start = j;
|
|
||||||
} else {
|
|
||||||
unsigned ntbins_, nqbins, ncbins, nsbins;
|
|
||||||
size_t reg_size, run_size;
|
|
||||||
uint32_t nregs;
|
|
||||||
uint64_t nrequests, nfills, nflushes, reruns;
|
|
||||||
size_t highruns, curruns;
|
|
||||||
|
|
||||||
if (gap_start != UINT_MAX) {
|
|
||||||
if (j > gap_start + 1) {
|
|
||||||
/* Gap of more than one size class. */
|
|
||||||
malloc_cprintf(write4, w4opaque,
|
|
||||||
"[%u..%u]\n", gap_start,
|
|
||||||
j - 1);
|
|
||||||
} else {
|
|
||||||
/* Gap of one size class. */
|
|
||||||
malloc_cprintf(write4, w4opaque,
|
|
||||||
"[%u]\n", gap_start);
|
|
||||||
}
|
|
||||||
gap_start = UINT_MAX;
|
|
||||||
}
|
|
||||||
CTL_GET("arenas.ntbins", &ntbins_, unsigned);
|
|
||||||
CTL_GET("arenas.nqbins", &nqbins, unsigned);
|
|
||||||
CTL_GET("arenas.ncbins", &ncbins, unsigned);
|
|
||||||
CTL_GET("arenas.nsbins", &nsbins, unsigned);
|
|
||||||
CTL_J_GET("arenas.bin.0.size", ®_size, size_t);
|
|
||||||
CTL_J_GET("arenas.bin.0.nregs", &nregs, uint32_t);
|
|
||||||
CTL_J_GET("arenas.bin.0.run_size", &run_size, size_t);
|
|
||||||
CTL_IJ_GET("stats.arenas.0.bins.0.nrequests",
|
|
||||||
&nrequests, uint64_t);
|
|
||||||
if (config_tcache) {
|
|
||||||
CTL_IJ_GET("stats.arenas.0.bins.0.nfills",
|
|
||||||
&nfills, uint64_t);
|
|
||||||
CTL_IJ_GET("stats.arenas.0.bins.0.nflushes",
|
|
||||||
&nflushes, uint64_t);
|
|
||||||
}
|
|
||||||
CTL_IJ_GET("stats.arenas.0.bins.0.nreruns", &reruns,
|
|
||||||
uint64_t);
|
|
||||||
CTL_IJ_GET("stats.arenas.0.bins.0.highruns", &highruns,
|
|
||||||
size_t);
|
|
||||||
CTL_IJ_GET("stats.arenas.0.bins.0.curruns", &curruns,
|
|
||||||
size_t);
|
|
||||||
if (config_tcache) {
|
|
||||||
malloc_cprintf(write4, w4opaque,
|
|
||||||
"%13u %1s %5zu %4u %3zu %10"PRIu64
|
|
||||||
" %9"PRIu64" %9"PRIu64" %9"PRIu64""
|
|
||||||
" %9"PRIu64" %7zu %7zu\n",
|
|
||||||
j,
|
|
||||||
j < ntbins_ ? "T" : j < ntbins_ + nqbins ?
|
|
||||||
"Q" : j < ntbins_ + nqbins + ncbins ? "C" :
|
|
||||||
j < ntbins_ + nqbins + ncbins + nsbins ? "S"
|
|
||||||
: "M",
|
|
||||||
reg_size, nregs, run_size / pagesize,
|
|
||||||
nrequests, nfills, nflushes, nruns, reruns,
|
|
||||||
highruns, curruns);
|
|
||||||
} else {
|
|
||||||
malloc_cprintf(write4, w4opaque,
|
|
||||||
"%13u %1s %5zu %4u %3zu %10"PRIu64
|
|
||||||
" %9"PRIu64" %9"PRIu64" %7zu %7zu\n",
|
|
||||||
j,
|
|
||||||
j < ntbins_ ? "T" : j < ntbins_ + nqbins ?
|
|
||||||
"Q" : j < ntbins_ + nqbins + ncbins ? "C" :
|
|
||||||
j < ntbins_ + nqbins + ncbins + nsbins ? "S"
|
|
||||||
: "M",
|
|
||||||
reg_size, nregs, run_size / pagesize,
|
|
||||||
nrequests, nruns, reruns, highruns,
|
|
||||||
curruns);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (gap_start != UINT_MAX) {
|
|
||||||
if (j > gap_start + 1) {
|
|
||||||
/* Gap of more than one size class. */
|
|
||||||
malloc_cprintf(write4, w4opaque, "[%u..%u]\n",
|
|
||||||
gap_start, j - 1);
|
|
||||||
} else {
|
|
||||||
/* Gap of one size class. */
|
|
||||||
malloc_cprintf(write4, w4opaque, "[%u]\n", gap_start);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
stats_arena_lruns_print(void (*write4)(void *, const char *, const char *,
|
|
||||||
const char *, const char *), void *w4opaque, unsigned i)
|
|
||||||
{
|
|
||||||
size_t pagesize, nlruns, j;
|
|
||||||
ssize_t gap_start;
|
|
||||||
|
|
||||||
CTL_GET("arenas.pagesize", &pagesize, size_t);
|
|
||||||
|
|
||||||
malloc_cprintf(write4, w4opaque,
|
|
||||||
"large: size pages nrequests maxruns curruns\n");
|
|
||||||
CTL_GET("arenas.nlruns", &nlruns, size_t);
|
|
||||||
for (j = 0, gap_start = -1; j < nlruns; j++) {
|
|
||||||
uint64_t nrequests;
|
|
||||||
size_t run_size, highruns, curruns;
|
|
||||||
|
|
||||||
CTL_IJ_GET("stats.arenas.0.lruns.0.nrequests", &nrequests,
|
|
||||||
uint64_t);
|
|
||||||
if (nrequests == 0) {
|
|
||||||
if (gap_start == -1)
|
|
||||||
gap_start = j;
|
|
||||||
} else {
|
|
||||||
CTL_J_GET("arenas.lrun.0.size", &run_size, size_t);
|
|
||||||
CTL_IJ_GET("stats.arenas.0.lruns.0.highruns", &highruns,
|
|
||||||
size_t);
|
|
||||||
CTL_IJ_GET("stats.arenas.0.lruns.0.curruns", &curruns,
|
|
||||||
size_t);
|
|
||||||
if (gap_start != -1) {
|
|
||||||
malloc_cprintf(write4, w4opaque, "[%zu]\n",
|
|
||||||
j - gap_start);
|
|
||||||
gap_start = -1;
|
|
||||||
}
|
|
||||||
malloc_cprintf(write4, w4opaque,
|
|
||||||
"%13zu %5zu %9"PRIu64" %9zu %9zu\n",
|
|
||||||
run_size, run_size / pagesize, nrequests, highruns,
|
|
||||||
curruns);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (gap_start != -1)
|
|
||||||
malloc_cprintf(write4, w4opaque, "[%zu]\n", j - gap_start);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
stats_arena_print(void (*write4)(void *, const char *, const char *,
|
|
||||||
const char *, const char *), void *w4opaque, unsigned i)
|
|
||||||
{
|
|
||||||
size_t pagesize, pactive, pdirty, mapped;
|
|
||||||
uint64_t npurge, nmadvise, purged;
|
|
||||||
size_t small_allocated;
|
|
||||||
uint64_t small_nmalloc, small_ndalloc;
|
|
||||||
size_t medium_allocated;
|
|
||||||
uint64_t medium_nmalloc, medium_ndalloc;
|
|
||||||
size_t large_allocated;
|
|
||||||
uint64_t large_nmalloc, large_ndalloc;
|
|
||||||
|
|
||||||
CTL_GET("arenas.pagesize", &pagesize, size_t);
|
|
||||||
|
|
||||||
CTL_I_GET("stats.arenas.0.pactive", &pactive, size_t);
|
|
||||||
CTL_I_GET("stats.arenas.0.pdirty", &pdirty, size_t);
|
|
||||||
CTL_I_GET("stats.arenas.0.npurge", &npurge, uint64_t);
|
|
||||||
CTL_I_GET("stats.arenas.0.nmadvise", &nmadvise, uint64_t);
|
|
||||||
CTL_I_GET("stats.arenas.0.purged", &purged, uint64_t);
|
|
||||||
malloc_cprintf(write4, w4opaque,
|
|
||||||
"dirty pages: %zu:%zu active:dirty, %"PRIu64" sweep%s,"
|
|
||||||
" %"PRIu64" madvise%s, %"PRIu64" purged\n",
|
|
||||||
pactive, pdirty, npurge, npurge == 1 ? "" : "s",
|
|
||||||
nmadvise, nmadvise == 1 ? "" : "s", purged);
|
|
||||||
|
|
||||||
malloc_cprintf(write4, w4opaque,
|
|
||||||
" allocated nmalloc ndalloc\n");
|
|
||||||
CTL_I_GET("stats.arenas.0.small.allocated", &small_allocated, size_t);
|
|
||||||
CTL_I_GET("stats.arenas.0.small.nmalloc", &small_nmalloc, uint64_t);
|
|
||||||
CTL_I_GET("stats.arenas.0.small.ndalloc", &small_ndalloc, uint64_t);
|
|
||||||
malloc_cprintf(write4, w4opaque,
|
|
||||||
"small: %12zu %12"PRIu64" %12"PRIu64"\n",
|
|
||||||
small_allocated, small_nmalloc, small_ndalloc);
|
|
||||||
CTL_I_GET("stats.arenas.0.medium.allocated", &medium_allocated, size_t);
|
|
||||||
CTL_I_GET("stats.arenas.0.medium.nmalloc", &medium_nmalloc, uint64_t);
|
|
||||||
CTL_I_GET("stats.arenas.0.medium.ndalloc", &medium_ndalloc, uint64_t);
|
|
||||||
malloc_cprintf(write4, w4opaque,
|
|
||||||
"medium: %12zu %12"PRIu64" %12"PRIu64"\n",
|
|
||||||
medium_allocated, medium_nmalloc, medium_ndalloc);
|
|
||||||
CTL_I_GET("stats.arenas.0.large.allocated", &large_allocated, size_t);
|
|
||||||
CTL_I_GET("stats.arenas.0.large.nmalloc", &large_nmalloc, uint64_t);
|
|
||||||
CTL_I_GET("stats.arenas.0.large.ndalloc", &large_ndalloc, uint64_t);
|
|
||||||
malloc_cprintf(write4, w4opaque,
|
|
||||||
"large: %12zu %12"PRIu64" %12"PRIu64"\n",
|
|
||||||
large_allocated, large_nmalloc, large_ndalloc);
|
|
||||||
malloc_cprintf(write4, w4opaque,
|
|
||||||
"total: %12zu %12"PRIu64" %12"PRIu64"\n",
|
|
||||||
small_allocated + medium_allocated + large_allocated,
|
|
||||||
small_nmalloc + medium_nmalloc + large_nmalloc,
|
|
||||||
small_ndalloc + medium_ndalloc + large_ndalloc);
|
|
||||||
malloc_cprintf(write4, w4opaque, "active: %12zu\n",
|
|
||||||
pactive * pagesize );
|
|
||||||
CTL_I_GET("stats.arenas.0.mapped", &mapped, size_t);
|
|
||||||
malloc_cprintf(write4, w4opaque, "mapped: %12zu\n", mapped);
|
|
||||||
|
|
||||||
stats_arena_bins_print(write4, w4opaque, i);
|
|
||||||
stats_arena_lruns_print(write4, w4opaque, i);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void
|
|
||||||
stats_print(void (*write4)(void *, const char *, const char *, const char *,
|
|
||||||
const char *), void *w4opaque, const char *opts)
|
|
||||||
{
|
|
||||||
uint64_t epoch;
|
|
||||||
size_t u64sz;
|
|
||||||
char s[UMAX2S_BUFSIZE];
|
|
||||||
bool general = true;
|
|
||||||
bool merged = true;
|
|
||||||
bool unmerged = true;
|
|
||||||
bool bins = true;
|
|
||||||
bool large = true;
|
|
||||||
|
|
||||||
/* Refresh stats, in case mallctl() was called by the application. */
|
|
||||||
epoch = 1;
|
|
||||||
u64sz = sizeof(uint64_t);
|
|
||||||
xmallctl("epoch", &epoch, &u64sz, &epoch, sizeof(uint64_t));
|
|
||||||
|
|
||||||
if (write4 == NULL) {
|
|
||||||
/*
|
|
||||||
* The caller did not provide an alternate write4 callback
|
|
||||||
* function, so use the default one. malloc_write4() is an
|
|
||||||
* inline function, so use malloc_message() directly here.
|
|
||||||
*/
|
|
||||||
write4 = JEMALLOC_P(malloc_message);
|
|
||||||
w4opaque = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
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:;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
write4(w4opaque, "___ Begin jemalloc statistics ___\n", "", "", "");
|
|
||||||
if (general) {
|
|
||||||
int err;
|
|
||||||
bool bv;
|
|
||||||
unsigned uv;
|
|
||||||
ssize_t ssv;
|
|
||||||
size_t sv, bsz, ssz;
|
|
||||||
|
|
||||||
bsz = sizeof(bool);
|
|
||||||
ssz = sizeof(size_t);
|
|
||||||
|
|
||||||
CTL_GET("config.debug", &bv, bool);
|
|
||||||
write4(w4opaque, "Assertions ", bv ? "enabled" : "disabled",
|
|
||||||
"\n", "");
|
|
||||||
|
|
||||||
write4(w4opaque, "Boolean JEMALLOC_OPTIONS: ", "", "", "");
|
|
||||||
if ((err = JEMALLOC_P(mallctl)("opt.abort", &bv, &bsz, NULL, 0))
|
|
||||||
== 0)
|
|
||||||
write4(w4opaque, bv ? "A" : "a", "", "", "");
|
|
||||||
if ((err = JEMALLOC_P(mallctl)("opt.prof", &bv, &bsz, NULL, 0))
|
|
||||||
== 0)
|
|
||||||
write4(w4opaque, bv ? "F" : "f", "", "", "");
|
|
||||||
if ((err = JEMALLOC_P(mallctl)("opt.junk", &bv, &bsz, NULL, 0))
|
|
||||||
== 0)
|
|
||||||
write4(w4opaque, bv ? "J" : "j", "", "", "");
|
|
||||||
if ((err = JEMALLOC_P(mallctl)("opt.prof_leak", &bv, &bsz, NULL,
|
|
||||||
0)) == 0)
|
|
||||||
write4(w4opaque, bv ? "L" : "l", "", "", "");
|
|
||||||
if ((err = JEMALLOC_P(mallctl)("opt.overcommit", &bv, &bsz,
|
|
||||||
NULL, 0)) == 0)
|
|
||||||
write4(w4opaque, bv ? "O" : "o", "", "", "");
|
|
||||||
write4(w4opaque, "P", "", "", "");
|
|
||||||
if ((err = JEMALLOC_P(mallctl)("opt.prof_udump", &bv, &bsz,
|
|
||||||
NULL, 0)) == 0)
|
|
||||||
write4(w4opaque, bv ? "U" : "u", "", "", "");
|
|
||||||
if ((err = JEMALLOC_P(mallctl)("opt.sysv", &bv, &bsz, NULL, 0))
|
|
||||||
== 0)
|
|
||||||
write4(w4opaque, bv ? "V" : "v", "", "", "");
|
|
||||||
if ((err = JEMALLOC_P(mallctl)("opt.xmalloc", &bv, &bsz, NULL,
|
|
||||||
0)) == 0)
|
|
||||||
write4(w4opaque, bv ? "X" : "x", "", "", "");
|
|
||||||
if ((err = JEMALLOC_P(mallctl)("opt.zero", &bv, &bsz, NULL, 0))
|
|
||||||
== 0)
|
|
||||||
write4(w4opaque, bv ? "Z" : "z", "", "", "");
|
|
||||||
write4(w4opaque, "\n", "", "", "");
|
|
||||||
|
|
||||||
write4(w4opaque, "CPUs: ", umax2s(ncpus, 10, s), "\n", "");
|
|
||||||
|
|
||||||
CTL_GET("arenas.narenas", &uv, unsigned);
|
|
||||||
write4(w4opaque, "Max arenas: ", umax2s(uv, 10, s), "\n", "");
|
|
||||||
|
|
||||||
write4(w4opaque, "Pointer size: ", umax2s(sizeof(void *), 10,
|
|
||||||
s), "\n", "");
|
|
||||||
|
|
||||||
CTL_GET("arenas.quantum", &sv, size_t);
|
|
||||||
write4(w4opaque, "Quantum size: ", umax2s(sv, 10, s), "\n", "");
|
|
||||||
|
|
||||||
CTL_GET("arenas.cacheline", &sv, size_t);
|
|
||||||
write4(w4opaque, "Cacheline size (assumed): ", umax2s(sv, 10,
|
|
||||||
s), "\n", "");
|
|
||||||
|
|
||||||
CTL_GET("arenas.subpage", &sv, size_t);
|
|
||||||
write4(w4opaque, "Subpage spacing: ", umax2s(sv, 10, s), "\n",
|
|
||||||
"");
|
|
||||||
|
|
||||||
CTL_GET("arenas.medium", &sv, size_t);
|
|
||||||
write4(w4opaque, "Medium spacing: ", umax2s(sv, 10, s), "\n",
|
|
||||||
"");
|
|
||||||
|
|
||||||
if ((err = JEMALLOC_P(mallctl)("arenas.tspace_min", &sv, &ssz,
|
|
||||||
NULL, 0)) == 0) {
|
|
||||||
write4(w4opaque, "Tiny 2^n-spaced sizes: [", umax2s(sv,
|
|
||||||
10, s), "..", "");
|
|
||||||
|
|
||||||
CTL_GET("arenas.tspace_max", &sv, size_t);
|
|
||||||
write4(w4opaque, umax2s(sv, 10, s), "]\n", "", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
CTL_GET("arenas.qspace_min", &sv, size_t);
|
|
||||||
write4(w4opaque, "Quantum-spaced sizes: [", umax2s(sv, 10, s),
|
|
||||||
"..", "");
|
|
||||||
CTL_GET("arenas.qspace_max", &sv, size_t);
|
|
||||||
write4(w4opaque, umax2s(sv, 10, s), "]\n", "", "");
|
|
||||||
|
|
||||||
CTL_GET("arenas.cspace_min", &sv, size_t);
|
|
||||||
write4(w4opaque, "Cacheline-spaced sizes: [", umax2s(sv, 10, s),
|
|
||||||
"..", "");
|
|
||||||
CTL_GET("arenas.cspace_max", &sv, size_t);
|
|
||||||
write4(w4opaque, umax2s(sv, 10, s), "]\n", "", "");
|
|
||||||
|
|
||||||
CTL_GET("arenas.sspace_min", &sv, size_t);
|
|
||||||
write4(w4opaque, "Subpage-spaced sizes: [", umax2s(sv, 10, s),
|
|
||||||
"..", "");
|
|
||||||
CTL_GET("arenas.sspace_max", &sv, size_t);
|
|
||||||
write4(w4opaque, umax2s(sv, 10, s), "]\n", "", "");
|
|
||||||
|
|
||||||
CTL_GET("arenas.medium_min", &sv, size_t);
|
|
||||||
write4(w4opaque, "Medium sizes: [", umax2s(sv, 10, s), "..",
|
|
||||||
"");
|
|
||||||
CTL_GET("arenas.medium_max", &sv, size_t);
|
|
||||||
write4(w4opaque, umax2s(sv, 10, s), "]\n", "", "");
|
|
||||||
|
|
||||||
CTL_GET("opt.lg_dirty_mult", &ssv, ssize_t);
|
|
||||||
if (ssv >= 0) {
|
|
||||||
write4(w4opaque,
|
|
||||||
"Min active:dirty page ratio per arena: ",
|
|
||||||
umax2s((1U << ssv), 10, s), ":1\n", "");
|
|
||||||
} else {
|
|
||||||
write4(w4opaque,
|
|
||||||
"Min active:dirty page ratio per arena: N/A\n", "",
|
|
||||||
"", "");
|
|
||||||
}
|
|
||||||
if ((err = JEMALLOC_P(mallctl)("opt.lg_tcache_nslots", &sv,
|
|
||||||
&ssz, NULL, 0)) == 0) {
|
|
||||||
size_t tcache_nslots, tcache_gc_sweep;
|
|
||||||
|
|
||||||
tcache_nslots = (1U << sv);
|
|
||||||
write4(w4opaque, "Thread cache slots per size class: ",
|
|
||||||
tcache_nslots ? umax2s(tcache_nslots, 10, s) :
|
|
||||||
"N/A", "\n", "");
|
|
||||||
|
|
||||||
CTL_GET("opt.lg_tcache_gc_sweep", &ssv, ssize_t);
|
|
||||||
tcache_gc_sweep = (1U << ssv);
|
|
||||||
write4(w4opaque, "Thread cache GC sweep interval: ",
|
|
||||||
tcache_nslots && ssv >= 0 ? umax2s(tcache_gc_sweep,
|
|
||||||
10, s) : "N/A", "\n", "");
|
|
||||||
}
|
|
||||||
if ((err = JEMALLOC_P(mallctl)("opt.prof", &bv, &bsz, NULL, 0))
|
|
||||||
== 0 && bv) {
|
|
||||||
xmallctl("opt.lg_prof_bt_max", &sv, &ssz, NULL, 0);
|
|
||||||
write4(w4opaque, "Maximum profile backtrace depth: ",
|
|
||||||
umax2s((1U << sv), 10, s), "\n", "");
|
|
||||||
|
|
||||||
xmallctl("opt.lg_prof_sample", &sv, &ssz, NULL, 0);
|
|
||||||
write4(w4opaque, "Average profile sample interval: ",
|
|
||||||
umax2s((1U << sv), 10, s), "", "");
|
|
||||||
write4(w4opaque, " (2^", umax2s(sv, 10, s), ")\n", "");
|
|
||||||
|
|
||||||
xmallctl("opt.lg_prof_interval", &sv, &ssz, NULL, 0);
|
|
||||||
write4(w4opaque, "Average profile dump interval: ",
|
|
||||||
umax2s((1U << sv), 10, s), "", "");
|
|
||||||
write4(w4opaque, " (2^", umax2s(sv, 10, s), ")\n", "");
|
|
||||||
}
|
|
||||||
CTL_GET("arenas.chunksize", &sv, size_t);
|
|
||||||
write4(w4opaque, "Chunk size: ", umax2s(sv, 10, s), "", "");
|
|
||||||
CTL_GET("opt.lg_chunk", &sv, size_t);
|
|
||||||
write4(w4opaque, " (2^", umax2s(sv, 10, s), ")\n", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef JEMALLOC_STATS
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
size_t ssz;
|
|
||||||
size_t allocated, active, mapped;
|
|
||||||
size_t chunks_current, chunks_high, swap_avail;
|
|
||||||
uint64_t chunks_total;
|
|
||||||
size_t huge_allocated;
|
|
||||||
uint64_t huge_nmalloc, huge_ndalloc;
|
|
||||||
|
|
||||||
ssz = sizeof(size_t);
|
|
||||||
|
|
||||||
CTL_GET("stats.allocated", &allocated, size_t);
|
|
||||||
CTL_GET("stats.active", &active, size_t);
|
|
||||||
CTL_GET("stats.mapped", &mapped, size_t);
|
|
||||||
malloc_cprintf(write4, w4opaque,
|
|
||||||
"Allocated: %zu, active: %zu, mapped: %zu\n", allocated,
|
|
||||||
active, mapped);
|
|
||||||
|
|
||||||
/* Print chunk stats. */
|
|
||||||
CTL_GET("stats.chunks.total", &chunks_total, uint64_t);
|
|
||||||
CTL_GET("stats.chunks.high", &chunks_high, size_t);
|
|
||||||
CTL_GET("stats.chunks.current", &chunks_current, size_t);
|
|
||||||
if ((err = JEMALLOC_P(mallctl)("swap.avail", &swap_avail, &ssz,
|
|
||||||
NULL, 0)) == 0) {
|
|
||||||
size_t lg_chunk;
|
|
||||||
|
|
||||||
malloc_cprintf(write4, w4opaque, "chunks: nchunks "
|
|
||||||
"highchunks curchunks swap_avail\n");
|
|
||||||
CTL_GET("opt.lg_chunk", &lg_chunk, size_t);
|
|
||||||
malloc_cprintf(write4, w4opaque,
|
|
||||||
" %13"PRIu64"%13zu%13zu%13zu\n",
|
|
||||||
chunks_total, chunks_high, chunks_current,
|
|
||||||
swap_avail << lg_chunk);
|
|
||||||
} else {
|
|
||||||
malloc_cprintf(write4, w4opaque, "chunks: nchunks "
|
|
||||||
"highchunks curchunks\n");
|
|
||||||
malloc_cprintf(write4, w4opaque,
|
|
||||||
" %13"PRIu64"%13zu%13zu\n",
|
|
||||||
chunks_total, chunks_high, chunks_current);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Print huge stats. */
|
|
||||||
CTL_GET("stats.huge.nmalloc", &huge_nmalloc, uint64_t);
|
|
||||||
CTL_GET("stats.huge.ndalloc", &huge_ndalloc, uint64_t);
|
|
||||||
CTL_GET("stats.huge.allocated", &huge_allocated, size_t);
|
|
||||||
malloc_cprintf(write4, w4opaque,
|
|
||||||
"huge: nmalloc ndalloc allocated\n");
|
|
||||||
malloc_cprintf(write4, w4opaque,
|
|
||||||
" %12"PRIu64" %12"PRIu64" %12zu\n",
|
|
||||||
huge_nmalloc, huge_ndalloc, huge_allocated);
|
|
||||||
|
|
||||||
if (merged) {
|
|
||||||
unsigned narenas;
|
|
||||||
|
|
||||||
CTL_GET("arenas.narenas", &narenas, unsigned);
|
|
||||||
{
|
|
||||||
bool initialized[narenas];
|
|
||||||
size_t isz;
|
|
||||||
unsigned i, ninitialized;
|
|
||||||
|
|
||||||
isz = sizeof(initialized);
|
|
||||||
xmallctl("arenas.initialized", initialized,
|
|
||||||
&isz, NULL, 0);
|
|
||||||
for (i = ninitialized = 0; i < narenas; i++) {
|
|
||||||
if (initialized[i])
|
|
||||||
ninitialized++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ninitialized > 1) {
|
|
||||||
/* Print merged arena stats. */
|
|
||||||
malloc_cprintf(write4, w4opaque,
|
|
||||||
"\nMerged arenas stats:\n");
|
|
||||||
stats_arena_print(write4, w4opaque,
|
|
||||||
narenas);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unmerged) {
|
|
||||||
unsigned narenas;
|
|
||||||
|
|
||||||
/* Print stats for each arena. */
|
|
||||||
|
|
||||||
CTL_GET("arenas.narenas", &narenas, unsigned);
|
|
||||||
{
|
|
||||||
bool initialized[narenas];
|
|
||||||
size_t isz;
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
isz = sizeof(initialized);
|
|
||||||
xmallctl("arenas.initialized", initialized,
|
|
||||||
&isz, NULL, 0);
|
|
||||||
|
|
||||||
for (i = 0; i < narenas; i++) {
|
|
||||||
if (initialized[i]) {
|
|
||||||
malloc_cprintf(write4, w4opaque,
|
|
||||||
"\narenas[%u]:\n", i);
|
|
||||||
stats_arena_print(write4,
|
|
||||||
w4opaque, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* #ifdef JEMALLOC_STATS */
|
|
||||||
write4(w4opaque, "--- End jemalloc statistics ---\n", "", "", "");
|
|
||||||
}
|
|
||||||
@@ -1,335 +0,0 @@
|
|||||||
#define JEMALLOC_TCACHE_C_
|
|
||||||
#include "jemalloc/internal/jemalloc_internal.h"
|
|
||||||
#ifdef JEMALLOC_TCACHE
|
|
||||||
/******************************************************************************/
|
|
||||||
/* Data. */
|
|
||||||
|
|
||||||
size_t opt_lg_tcache_nslots = LG_TCACHE_NSLOTS_DEFAULT;
|
|
||||||
ssize_t opt_lg_tcache_gc_sweep = LG_TCACHE_GC_SWEEP_DEFAULT;
|
|
||||||
|
|
||||||
/* Map of thread-specific caches. */
|
|
||||||
__thread tcache_t *tcache_tls JEMALLOC_ATTR(tls_model("initial-exec"));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Same contents as tcache, but initialized such that the TSD destructor is
|
|
||||||
* called when a thread exits, so that the cache can be cleaned up.
|
|
||||||
*/
|
|
||||||
static pthread_key_t tcache_tsd;
|
|
||||||
|
|
||||||
size_t tcache_nslots;
|
|
||||||
unsigned tcache_gc_incr;
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
/* Function prototypes for non-inline static functions. */
|
|
||||||
|
|
||||||
static void tcache_thread_cleanup(void *arg);
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
void *
|
|
||||||
tcache_alloc_hard(tcache_t *tcache, tcache_bin_t *tbin, size_t binind)
|
|
||||||
{
|
|
||||||
void *ret;
|
|
||||||
|
|
||||||
arena_tcache_fill(tcache->arena, tbin, binind
|
|
||||||
#ifdef JEMALLOC_PROF
|
|
||||||
, tcache->prof_accumbytes
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
#ifdef JEMALLOC_PROF
|
|
||||||
tcache->prof_accumbytes = 0;
|
|
||||||
#endif
|
|
||||||
ret = tcache_bin_alloc(tbin);
|
|
||||||
|
|
||||||
return (ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
tcache_bin_flush(tcache_bin_t *tbin, size_t binind, unsigned rem
|
|
||||||
#ifdef JEMALLOC_PROF
|
|
||||||
, tcache_t *tcache
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
{
|
|
||||||
arena_chunk_t *chunk;
|
|
||||||
arena_t *arena;
|
|
||||||
void *ptr;
|
|
||||||
unsigned i, ndeferred, ncached;
|
|
||||||
|
|
||||||
for (ndeferred = tbin->ncached - rem; ndeferred > 0;) {
|
|
||||||
ncached = ndeferred;
|
|
||||||
/* Lock the arena associated with the first object. */
|
|
||||||
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(tbin->slots[0]);
|
|
||||||
arena = chunk->arena;
|
|
||||||
malloc_mutex_lock(&arena->lock);
|
|
||||||
#ifdef JEMALLOC_PROF
|
|
||||||
if (arena == tcache->arena) {
|
|
||||||
arena_prof_accum(arena, tcache->prof_accumbytes);
|
|
||||||
tcache->prof_accumbytes = 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
/* Deallocate every object that belongs to the locked arena. */
|
|
||||||
for (i = ndeferred = 0; i < ncached; i++) {
|
|
||||||
ptr = tbin->slots[i];
|
|
||||||
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
|
||||||
if (chunk->arena == arena) {
|
|
||||||
size_t pageind = (((uintptr_t)ptr -
|
|
||||||
(uintptr_t)chunk) >> PAGE_SHIFT);
|
|
||||||
arena_chunk_map_t *mapelm =
|
|
||||||
&chunk->map[pageind];
|
|
||||||
arena_dalloc_bin(arena, chunk, ptr, mapelm);
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* This object was allocated via a different
|
|
||||||
* arena than the one that is currently locked.
|
|
||||||
* Stash the object, so that it can be handled
|
|
||||||
* in a future pass.
|
|
||||||
*/
|
|
||||||
tbin->slots[ndeferred] = ptr;
|
|
||||||
ndeferred++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef JEMALLOC_STATS
|
|
||||||
arena->bins[binind].stats.nflushes++;
|
|
||||||
{
|
|
||||||
arena_bin_t *bin = &arena->bins[binind];
|
|
||||||
bin->stats.nrequests += tbin->tstats.nrequests;
|
|
||||||
if (bin->reg_size <= small_maxclass) {
|
|
||||||
arena->stats.nmalloc_small +=
|
|
||||||
tbin->tstats.nrequests;
|
|
||||||
} else {
|
|
||||||
arena->stats.nmalloc_medium +=
|
|
||||||
tbin->tstats.nrequests;
|
|
||||||
}
|
|
||||||
tbin->tstats.nrequests = 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
malloc_mutex_unlock(&arena->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rem > 0) {
|
|
||||||
/*
|
|
||||||
* Shift the remaining valid pointers to the base of the slots
|
|
||||||
* array.
|
|
||||||
*/
|
|
||||||
memmove(&tbin->slots[0], &tbin->slots[tbin->ncached - rem],
|
|
||||||
rem * sizeof(void *));
|
|
||||||
}
|
|
||||||
tbin->ncached = rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
tcache_bin_t *
|
|
||||||
tcache_bin_create(arena_t *arena)
|
|
||||||
{
|
|
||||||
tcache_bin_t *ret;
|
|
||||||
size_t tsize;
|
|
||||||
|
|
||||||
tsize = sizeof(tcache_bin_t) + (sizeof(void *) * (tcache_nslots - 1));
|
|
||||||
if (tsize <= small_maxclass)
|
|
||||||
ret = (tcache_bin_t *)arena_malloc_small(arena, tsize, false);
|
|
||||||
else if (tsize <= bin_maxclass)
|
|
||||||
ret = (tcache_bin_t *)arena_malloc_medium(arena, tsize, false);
|
|
||||||
else
|
|
||||||
ret = (tcache_bin_t *)imalloc(tsize);
|
|
||||||
if (ret == NULL)
|
|
||||||
return (NULL);
|
|
||||||
#ifdef JEMALLOC_STATS
|
|
||||||
memset(&ret->tstats, 0, sizeof(tcache_bin_stats_t));
|
|
||||||
#endif
|
|
||||||
ret->low_water = 0;
|
|
||||||
ret->high_water = 0;
|
|
||||||
ret->ncached = 0;
|
|
||||||
|
|
||||||
return (ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
tcache_bin_destroy(tcache_t *tcache, tcache_bin_t *tbin, unsigned binind)
|
|
||||||
{
|
|
||||||
arena_t *arena;
|
|
||||||
arena_chunk_t *chunk;
|
|
||||||
size_t pageind, tsize;
|
|
||||||
arena_chunk_map_t *mapelm;
|
|
||||||
|
|
||||||
chunk = CHUNK_ADDR2BASE(tbin);
|
|
||||||
arena = chunk->arena;
|
|
||||||
pageind = (((uintptr_t)tbin - (uintptr_t)chunk) >> PAGE_SHIFT);
|
|
||||||
mapelm = &chunk->map[pageind];
|
|
||||||
|
|
||||||
#ifdef JEMALLOC_STATS
|
|
||||||
if (tbin->tstats.nrequests != 0) {
|
|
||||||
arena_t *arena = tcache->arena;
|
|
||||||
arena_bin_t *bin = &arena->bins[binind];
|
|
||||||
malloc_mutex_lock(&arena->lock);
|
|
||||||
bin->stats.nrequests += tbin->tstats.nrequests;
|
|
||||||
if (bin->reg_size <= small_maxclass)
|
|
||||||
arena->stats.nmalloc_small += tbin->tstats.nrequests;
|
|
||||||
else
|
|
||||||
arena->stats.nmalloc_medium += tbin->tstats.nrequests;
|
|
||||||
malloc_mutex_unlock(&arena->lock);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
assert(tbin->ncached == 0);
|
|
||||||
tsize = sizeof(tcache_bin_t) + (sizeof(void *) * (tcache_nslots - 1));
|
|
||||||
if (tsize <= bin_maxclass) {
|
|
||||||
malloc_mutex_lock(&arena->lock);
|
|
||||||
arena_dalloc_bin(arena, chunk, tbin, mapelm);
|
|
||||||
malloc_mutex_unlock(&arena->lock);
|
|
||||||
} else
|
|
||||||
idalloc(tbin);
|
|
||||||
}
|
|
||||||
|
|
||||||
tcache_t *
|
|
||||||
tcache_create(arena_t *arena)
|
|
||||||
{
|
|
||||||
tcache_t *tcache;
|
|
||||||
|
|
||||||
if (sizeof(tcache_t) + (sizeof(tcache_bin_t *) * (nbins - 1)) <=
|
|
||||||
small_maxclass) {
|
|
||||||
tcache = (tcache_t *)arena_malloc_small(arena, sizeof(tcache_t)
|
|
||||||
+ (sizeof(tcache_bin_t *) * (nbins - 1)), true);
|
|
||||||
} else if (sizeof(tcache_t) + (sizeof(tcache_bin_t *) * (nbins - 1)) <=
|
|
||||||
bin_maxclass) {
|
|
||||||
tcache = (tcache_t *)arena_malloc_medium(arena, sizeof(tcache_t)
|
|
||||||
+ (sizeof(tcache_bin_t *) * (nbins - 1)), true);
|
|
||||||
} else {
|
|
||||||
tcache = (tcache_t *)icalloc(sizeof(tcache_t) +
|
|
||||||
(sizeof(tcache_bin_t *) * (nbins - 1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tcache == NULL)
|
|
||||||
return (NULL);
|
|
||||||
|
|
||||||
#ifdef JEMALLOC_STATS
|
|
||||||
/* Link into list of extant tcaches. */
|
|
||||||
malloc_mutex_lock(&arena->lock);
|
|
||||||
ql_elm_new(tcache, link);
|
|
||||||
ql_tail_insert(&arena->tcache_ql, tcache, link);
|
|
||||||
malloc_mutex_unlock(&arena->lock);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
tcache->arena = arena;
|
|
||||||
|
|
||||||
tcache_tls = tcache;
|
|
||||||
pthread_setspecific(tcache_tsd, tcache);
|
|
||||||
|
|
||||||
return (tcache);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
tcache_destroy(tcache_t *tcache)
|
|
||||||
{
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
#ifdef JEMALLOC_STATS
|
|
||||||
/* Unlink from list of extant tcaches. */
|
|
||||||
malloc_mutex_lock(&tcache->arena->lock);
|
|
||||||
ql_remove(&tcache->arena->tcache_ql, tcache, link);
|
|
||||||
tcache_stats_merge(tcache, tcache->arena);
|
|
||||||
malloc_mutex_unlock(&tcache->arena->lock);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (i = 0; i < nbins; i++) {
|
|
||||||
tcache_bin_t *tbin = tcache->tbins[i];
|
|
||||||
if (tbin != NULL) {
|
|
||||||
tcache_bin_flush(tbin, i, 0
|
|
||||||
#ifdef JEMALLOC_PROF
|
|
||||||
, tcache
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
tcache_bin_destroy(tcache, tbin, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef JEMALLOC_PROF
|
|
||||||
if (tcache->prof_accumbytes > 0) {
|
|
||||||
malloc_mutex_lock(&tcache->arena->lock);
|
|
||||||
arena_prof_accum(tcache->arena, tcache->prof_accumbytes);
|
|
||||||
malloc_mutex_unlock(&tcache->arena->lock);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (arena_salloc(tcache) <= bin_maxclass) {
|
|
||||||
arena_chunk_t *chunk = CHUNK_ADDR2BASE(tcache);
|
|
||||||
arena_t *arena = chunk->arena;
|
|
||||||
size_t pageind = (((uintptr_t)tcache - (uintptr_t)chunk) >>
|
|
||||||
PAGE_SHIFT);
|
|
||||||
arena_chunk_map_t *mapelm = &chunk->map[pageind];
|
|
||||||
|
|
||||||
malloc_mutex_lock(&arena->lock);
|
|
||||||
arena_dalloc_bin(arena, chunk, tcache, mapelm);
|
|
||||||
malloc_mutex_unlock(&arena->lock);
|
|
||||||
} else
|
|
||||||
idalloc(tcache);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
tcache_thread_cleanup(void *arg)
|
|
||||||
{
|
|
||||||
tcache_t *tcache = (tcache_t *)arg;
|
|
||||||
|
|
||||||
assert(tcache == tcache_tls);
|
|
||||||
if (tcache != NULL) {
|
|
||||||
assert(tcache != (void *)(uintptr_t)1);
|
|
||||||
tcache_destroy(tcache);
|
|
||||||
tcache_tls = (void *)(uintptr_t)1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef JEMALLOC_STATS
|
|
||||||
void
|
|
||||||
tcache_stats_merge(tcache_t *tcache, arena_t *arena)
|
|
||||||
{
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
/* Merge and reset tcache stats. */
|
|
||||||
for (i = 0; i < mbin0; i++) {
|
|
||||||
arena_bin_t *bin = &arena->bins[i];
|
|
||||||
tcache_bin_t *tbin = tcache->tbins[i];
|
|
||||||
if (tbin != NULL) {
|
|
||||||
bin->stats.nrequests += tbin->tstats.nrequests;
|
|
||||||
arena->stats.nmalloc_small += tbin->tstats.nrequests;
|
|
||||||
tbin->tstats.nrequests = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (; i < nbins; i++) {
|
|
||||||
arena_bin_t *bin = &arena->bins[i];
|
|
||||||
tcache_bin_t *tbin = tcache->tbins[i];
|
|
||||||
if (tbin != NULL) {
|
|
||||||
bin->stats.nrequests += tbin->tstats.nrequests;
|
|
||||||
arena->stats.nmalloc_medium += tbin->tstats.nrequests;
|
|
||||||
tbin->tstats.nrequests = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void
|
|
||||||
tcache_boot(void)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (opt_lg_tcache_nslots > 0) {
|
|
||||||
tcache_nslots = (1U << opt_lg_tcache_nslots);
|
|
||||||
|
|
||||||
/* Compute incremental GC event threshold. */
|
|
||||||
if (opt_lg_tcache_gc_sweep >= 0) {
|
|
||||||
tcache_gc_incr = ((1U << opt_lg_tcache_gc_sweep) /
|
|
||||||
nbins) + (((1U << opt_lg_tcache_gc_sweep) % nbins ==
|
|
||||||
0) ? 0 : 1);
|
|
||||||
} else
|
|
||||||
tcache_gc_incr = 0;
|
|
||||||
} else
|
|
||||||
tcache_nslots = 0;
|
|
||||||
|
|
||||||
if (tcache_nslots != 0) {
|
|
||||||
if (pthread_key_create(&tcache_tsd, tcache_thread_cleanup) !=
|
|
||||||
0) {
|
|
||||||
malloc_write4("<jemalloc>",
|
|
||||||
": Error in pthread_key_create()\n", "", "");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/******************************************************************************/
|
|
||||||
#endif /* JEMALLOC_TCACHE */
|
|
||||||
2703
src/arena.c
Normal file
2703
src/arena.c
Normal file
File diff suppressed because it is too large
Load Diff
2
src/atomic.c
Normal file
2
src/atomic.c
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#define JEMALLOC_ATOMIC_C_
|
||||||
|
#include "jemalloc/internal/jemalloc_internal.h"
|
||||||
@@ -32,7 +32,7 @@ base_pages_alloc(size_t minsize)
|
|||||||
assert(minsize != 0);
|
assert(minsize != 0);
|
||||||
csize = CHUNK_CEILING(minsize);
|
csize = CHUNK_CEILING(minsize);
|
||||||
zero = false;
|
zero = false;
|
||||||
base_pages = chunk_alloc(csize, &zero);
|
base_pages = chunk_alloc(csize, true, &zero);
|
||||||
if (base_pages == NULL)
|
if (base_pages == NULL)
|
||||||
return (true);
|
return (true);
|
||||||
base_next_addr = base_pages;
|
base_next_addr = base_pages;
|
||||||
90
src/bitmap.c
Normal file
90
src/bitmap.c
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
#define JEMALLOC_BITMAP_C_
|
||||||
|
#include "jemalloc/internal/jemalloc_internal.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/* Function prototypes for non-inline static functions. */
|
||||||
|
|
||||||
|
static size_t bits2groups(size_t nbits);
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
bits2groups(size_t nbits)
|
||||||
|
{
|
||||||
|
|
||||||
|
return ((nbits >> LG_BITMAP_GROUP_NBITS) +
|
||||||
|
!!(nbits & BITMAP_GROUP_NBITS_MASK));
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = 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 = bits2groups(group_count);
|
||||||
|
}
|
||||||
|
binfo->levels[i].group_offset = binfo->levels[i-1].group_offset
|
||||||
|
+ group_count;
|
||||||
|
binfo->nlevels = i;
|
||||||
|
binfo->nbits = nbits;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
bitmap_info_ngroups(const bitmap_info_t *binfo)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (binfo->levels[binfo->nlevels].group_offset << LG_SIZEOF_BITMAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
bitmap_size(size_t nbits)
|
||||||
|
{
|
||||||
|
bitmap_info_t binfo;
|
||||||
|
|
||||||
|
bitmap_info_init(&binfo, nbits);
|
||||||
|
return (bitmap_info_ngroups(&binfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo)
|
||||||
|
{
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
memset(bitmap, 0xffU, binfo->levels[binfo->nlevels].group_offset <<
|
||||||
|
LG_SIZEOF_BITMAP);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,11 +14,15 @@ malloc_mutex_t chunks_mtx;
|
|||||||
chunk_stats_t stats_chunks;
|
chunk_stats_t stats_chunks;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_IVSALLOC
|
||||||
|
rtree_t *chunks_rtree;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Various chunk-related settings. */
|
/* Various chunk-related settings. */
|
||||||
size_t chunksize;
|
size_t chunksize;
|
||||||
size_t chunksize_mask; /* (chunksize - 1). */
|
size_t chunksize_mask; /* (chunksize - 1). */
|
||||||
size_t chunk_npages;
|
size_t chunk_npages;
|
||||||
size_t arena_chunk_header_npages;
|
size_t map_bias;
|
||||||
size_t arena_maxclass; /* Max size class for arenas. */
|
size_t arena_maxclass; /* Max size class for arenas. */
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@@ -30,7 +34,7 @@ size_t arena_maxclass; /* Max size class for arenas. */
|
|||||||
* advantage of them if they are returned.
|
* advantage of them if they are returned.
|
||||||
*/
|
*/
|
||||||
void *
|
void *
|
||||||
chunk_alloc(size_t size, bool *zero)
|
chunk_alloc(size_t size, bool base, bool *zero)
|
||||||
{
|
{
|
||||||
void *ret;
|
void *ret;
|
||||||
|
|
||||||
@@ -63,10 +67,18 @@ chunk_alloc(size_t size, bool *zero)
|
|||||||
/* All strategies for allocation failed. */
|
/* All strategies for allocation failed. */
|
||||||
ret = NULL;
|
ret = NULL;
|
||||||
RETURN:
|
RETURN:
|
||||||
|
#ifdef JEMALLOC_IVSALLOC
|
||||||
|
if (base == false && ret != NULL) {
|
||||||
|
if (rtree_set(chunks_rtree, (uintptr_t)ret, ret)) {
|
||||||
|
chunk_dealloc(ret, size);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#if (defined(JEMALLOC_STATS) || defined(JEMALLOC_PROF))
|
#if (defined(JEMALLOC_STATS) || defined(JEMALLOC_PROF))
|
||||||
if (ret != NULL) {
|
if (ret != NULL) {
|
||||||
# ifdef JEMALLOC_PROF
|
# ifdef JEMALLOC_PROF
|
||||||
bool udump;
|
bool gdump;
|
||||||
# endif
|
# endif
|
||||||
malloc_mutex_lock(&chunks_mtx);
|
malloc_mutex_lock(&chunks_mtx);
|
||||||
# ifdef JEMALLOC_STATS
|
# ifdef JEMALLOC_STATS
|
||||||
@@ -76,17 +88,17 @@ RETURN:
|
|||||||
if (stats_chunks.curchunks > stats_chunks.highchunks) {
|
if (stats_chunks.curchunks > stats_chunks.highchunks) {
|
||||||
stats_chunks.highchunks = stats_chunks.curchunks;
|
stats_chunks.highchunks = stats_chunks.curchunks;
|
||||||
# ifdef JEMALLOC_PROF
|
# ifdef JEMALLOC_PROF
|
||||||
udump = true;
|
gdump = true;
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
# ifdef JEMALLOC_PROF
|
# ifdef JEMALLOC_PROF
|
||||||
else
|
else
|
||||||
udump = false;
|
gdump = false;
|
||||||
# endif
|
# endif
|
||||||
malloc_mutex_unlock(&chunks_mtx);
|
malloc_mutex_unlock(&chunks_mtx);
|
||||||
# ifdef JEMALLOC_PROF
|
# ifdef JEMALLOC_PROF
|
||||||
if (opt_prof && opt_prof_udump && udump)
|
if (opt_prof && opt_prof_gdump && gdump)
|
||||||
prof_udump();
|
prof_gdump();
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -104,6 +116,9 @@ chunk_dealloc(void *chunk, size_t size)
|
|||||||
assert(size != 0);
|
assert(size != 0);
|
||||||
assert((size & chunksize_mask) == 0);
|
assert((size & chunksize_mask) == 0);
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_IVSALLOC
|
||||||
|
rtree_set(chunks_rtree, (uintptr_t)chunk, NULL);
|
||||||
|
#endif
|
||||||
#if (defined(JEMALLOC_STATS) || defined(JEMALLOC_PROF))
|
#if (defined(JEMALLOC_STATS) || defined(JEMALLOC_PROF))
|
||||||
malloc_mutex_lock(&chunks_mtx);
|
malloc_mutex_lock(&chunks_mtx);
|
||||||
stats_chunks.curchunks -= (size / chunksize);
|
stats_chunks.curchunks -= (size / chunksize);
|
||||||
@@ -126,7 +141,7 @@ chunk_boot(void)
|
|||||||
{
|
{
|
||||||
|
|
||||||
/* Set variables according to the value of opt_lg_chunk. */
|
/* Set variables according to the value of opt_lg_chunk. */
|
||||||
chunksize = (1LU << opt_lg_chunk);
|
chunksize = (ZU(1) << opt_lg_chunk);
|
||||||
assert(chunksize >= PAGE_SIZE);
|
assert(chunksize >= PAGE_SIZE);
|
||||||
chunksize_mask = chunksize - 1;
|
chunksize_mask = chunksize - 1;
|
||||||
chunk_npages = (chunksize >> PAGE_SHIFT);
|
chunk_npages = (chunksize >> PAGE_SHIFT);
|
||||||
@@ -136,15 +151,21 @@ chunk_boot(void)
|
|||||||
return (true);
|
return (true);
|
||||||
memset(&stats_chunks, 0, sizeof(chunk_stats_t));
|
memset(&stats_chunks, 0, sizeof(chunk_stats_t));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef JEMALLOC_SWAP
|
#ifdef JEMALLOC_SWAP
|
||||||
if (chunk_swap_boot())
|
if (chunk_swap_boot())
|
||||||
return (true);
|
return (true);
|
||||||
#endif
|
#endif
|
||||||
|
if (chunk_mmap_boot())
|
||||||
|
return (true);
|
||||||
#ifdef JEMALLOC_DSS
|
#ifdef JEMALLOC_DSS
|
||||||
if (chunk_dss_boot())
|
if (chunk_dss_boot())
|
||||||
return (true);
|
return (true);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef JEMALLOC_IVSALLOC
|
||||||
|
chunks_rtree = rtree_new((ZU(1) << (LG_SIZEOF_PTR+3)) - opt_lg_chunk);
|
||||||
|
if (chunks_rtree == NULL)
|
||||||
|
return (true);
|
||||||
|
#endif
|
||||||
|
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
@@ -199,6 +199,22 @@ chunk_dealloc_dss_record(void *chunk, size_t size)
|
|||||||
return (node);
|
return (node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
chunk_in_dss(void *chunk)
|
||||||
|
{
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
malloc_mutex_lock(&dss_mtx);
|
||||||
|
if ((uintptr_t)chunk >= (uintptr_t)dss_base
|
||||||
|
&& (uintptr_t)chunk < (uintptr_t)dss_max)
|
||||||
|
ret = true;
|
||||||
|
else
|
||||||
|
ret = false;
|
||||||
|
malloc_mutex_unlock(&dss_mtx);
|
||||||
|
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
chunk_dealloc_dss(void *chunk, size_t size)
|
chunk_dealloc_dss(void *chunk, size_t size)
|
||||||
{
|
{
|
||||||
@@ -6,31 +6,36 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Used by chunk_alloc_mmap() to decide whether to attempt the fast path and
|
* Used by chunk_alloc_mmap() to decide whether to attempt the fast path and
|
||||||
* potentially avoid some system calls. We can get away without TLS here,
|
* potentially avoid some system calls.
|
||||||
* since the state of mmap_unaligned only affects performance, rather than
|
|
||||||
* correct function.
|
|
||||||
*/
|
*/
|
||||||
static
|
|
||||||
#ifndef NO_TLS
|
#ifndef NO_TLS
|
||||||
__thread
|
static __thread bool mmap_unaligned_tls
|
||||||
|
JEMALLOC_ATTR(tls_model("initial-exec"));
|
||||||
|
#define MMAP_UNALIGNED_GET() mmap_unaligned_tls
|
||||||
|
#define MMAP_UNALIGNED_SET(v) do { \
|
||||||
|
mmap_unaligned_tls = (v); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
static pthread_key_t mmap_unaligned_tsd;
|
||||||
|
#define MMAP_UNALIGNED_GET() ((bool)pthread_getspecific(mmap_unaligned_tsd))
|
||||||
|
#define MMAP_UNALIGNED_SET(v) do { \
|
||||||
|
pthread_setspecific(mmap_unaligned_tsd, (void *)(v)); \
|
||||||
|
} while (0)
|
||||||
#endif
|
#endif
|
||||||
bool mmap_unaligned
|
|
||||||
#ifndef NO_TLS
|
|
||||||
JEMALLOC_ATTR(tls_model("initial-exec"))
|
|
||||||
#endif
|
|
||||||
;
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* Function prototypes for non-inline static functions. */
|
/* Function prototypes for non-inline static functions. */
|
||||||
|
|
||||||
static void *pages_map(void *addr, size_t size);
|
static void *pages_map(void *addr, size_t size, bool noreserve);
|
||||||
static void pages_unmap(void *addr, size_t size);
|
static void pages_unmap(void *addr, size_t size);
|
||||||
static void *chunk_alloc_mmap_slow(size_t size, bool unaligned);
|
static void *chunk_alloc_mmap_slow(size_t size, bool unaligned,
|
||||||
|
bool noreserve);
|
||||||
|
static void *chunk_alloc_mmap_internal(size_t size, bool noreserve);
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
pages_map(void *addr, size_t size)
|
pages_map(void *addr, size_t size, bool noreserve)
|
||||||
{
|
{
|
||||||
void *ret;
|
void *ret;
|
||||||
|
|
||||||
@@ -38,8 +43,12 @@ pages_map(void *addr, size_t size)
|
|||||||
* We don't use MAP_FIXED here, because it can cause the *replacement*
|
* We don't use MAP_FIXED here, because it can cause the *replacement*
|
||||||
* of existing mappings, and we only want to create new mappings.
|
* of existing mappings, and we only want to create new mappings.
|
||||||
*/
|
*/
|
||||||
ret = mmap(addr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON,
|
int flags = MAP_PRIVATE | MAP_ANON;
|
||||||
-1, 0);
|
#ifdef MAP_NORESERVE
|
||||||
|
if (noreserve)
|
||||||
|
flags |= MAP_NORESERVE;
|
||||||
|
#endif
|
||||||
|
ret = mmap(addr, size, PROT_READ | PROT_WRITE, flags, -1, 0);
|
||||||
assert(ret != NULL);
|
assert(ret != NULL);
|
||||||
|
|
||||||
if (ret == MAP_FAILED)
|
if (ret == MAP_FAILED)
|
||||||
@@ -49,11 +58,12 @@ pages_map(void *addr, size_t size)
|
|||||||
* We succeeded in mapping memory, but not in the right place.
|
* We succeeded in mapping memory, but not in the right place.
|
||||||
*/
|
*/
|
||||||
if (munmap(ret, size) == -1) {
|
if (munmap(ret, size) == -1) {
|
||||||
char buf[STRERROR_BUF];
|
char buf[BUFERROR_BUF];
|
||||||
|
|
||||||
strerror_r(errno, buf, sizeof(buf));
|
buferror(errno, buf, sizeof(buf));
|
||||||
malloc_write4("<jemalloc>", ": Error in munmap(): ",
|
malloc_write("<jemalloc>: Error in munmap(): ");
|
||||||
buf, "\n");
|
malloc_write(buf);
|
||||||
|
malloc_write("\n");
|
||||||
if (opt_abort)
|
if (opt_abort)
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
@@ -70,17 +80,19 @@ pages_unmap(void *addr, size_t size)
|
|||||||
{
|
{
|
||||||
|
|
||||||
if (munmap(addr, size) == -1) {
|
if (munmap(addr, size) == -1) {
|
||||||
char buf[STRERROR_BUF];
|
char buf[BUFERROR_BUF];
|
||||||
|
|
||||||
strerror_r(errno, buf, sizeof(buf));
|
buferror(errno, buf, sizeof(buf));
|
||||||
malloc_write4("<jemalloc>", ": Error in munmap(): ", buf, "\n");
|
malloc_write("<jemalloc>: Error in munmap(): ");
|
||||||
|
malloc_write(buf);
|
||||||
|
malloc_write("\n");
|
||||||
if (opt_abort)
|
if (opt_abort)
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
chunk_alloc_mmap_slow(size_t size, bool unaligned)
|
chunk_alloc_mmap_slow(size_t size, bool unaligned, bool noreserve)
|
||||||
{
|
{
|
||||||
void *ret;
|
void *ret;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
@@ -89,7 +101,7 @@ chunk_alloc_mmap_slow(size_t size, bool unaligned)
|
|||||||
if (size + chunksize <= size)
|
if (size + chunksize <= size)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
ret = pages_map(NULL, size + chunksize);
|
ret = pages_map(NULL, size + chunksize, noreserve);
|
||||||
if (ret == NULL)
|
if (ret == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
@@ -120,13 +132,13 @@ chunk_alloc_mmap_slow(size_t size, bool unaligned)
|
|||||||
* method.
|
* method.
|
||||||
*/
|
*/
|
||||||
if (unaligned == false)
|
if (unaligned == false)
|
||||||
mmap_unaligned = false;
|
MMAP_UNALIGNED_SET(false);
|
||||||
|
|
||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
static void *
|
||||||
chunk_alloc_mmap(size_t size)
|
chunk_alloc_mmap_internal(size_t size, bool noreserve)
|
||||||
{
|
{
|
||||||
void *ret;
|
void *ret;
|
||||||
|
|
||||||
@@ -158,25 +170,26 @@ chunk_alloc_mmap(size_t size)
|
|||||||
* fast method next time.
|
* fast method next time.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (mmap_unaligned == false) {
|
if (MMAP_UNALIGNED_GET() == false) {
|
||||||
size_t offset;
|
size_t offset;
|
||||||
|
|
||||||
ret = pages_map(NULL, size);
|
ret = pages_map(NULL, size, noreserve);
|
||||||
if (ret == NULL)
|
if (ret == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
offset = CHUNK_ADDR2OFFSET(ret);
|
offset = CHUNK_ADDR2OFFSET(ret);
|
||||||
if (offset != 0) {
|
if (offset != 0) {
|
||||||
mmap_unaligned = true;
|
MMAP_UNALIGNED_SET(true);
|
||||||
/* Try to extend chunk boundary. */
|
/* Try to extend chunk boundary. */
|
||||||
if (pages_map((void *)((uintptr_t)ret + size),
|
if (pages_map((void *)((uintptr_t)ret + size),
|
||||||
chunksize - offset) == NULL) {
|
chunksize - offset, noreserve) == NULL) {
|
||||||
/*
|
/*
|
||||||
* Extension failed. Clean up, then revert to
|
* Extension failed. Clean up, then revert to
|
||||||
* the reliable-but-expensive method.
|
* the reliable-but-expensive method.
|
||||||
*/
|
*/
|
||||||
pages_unmap(ret, size);
|
pages_unmap(ret, size);
|
||||||
ret = chunk_alloc_mmap_slow(size, true);
|
ret = chunk_alloc_mmap_slow(size, true,
|
||||||
|
noreserve);
|
||||||
} else {
|
} else {
|
||||||
/* Clean up unneeded leading space. */
|
/* Clean up unneeded leading space. */
|
||||||
pages_unmap(ret, chunksize - offset);
|
pages_unmap(ret, chunksize - offset);
|
||||||
@@ -185,14 +198,42 @@ chunk_alloc_mmap(size_t size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
ret = chunk_alloc_mmap_slow(size, false);
|
ret = chunk_alloc_mmap_slow(size, false, noreserve);
|
||||||
|
|
||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
chunk_alloc_mmap(size_t size)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (chunk_alloc_mmap_internal(size, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
chunk_alloc_mmap_noreserve(size_t size)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (chunk_alloc_mmap_internal(size, true));
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
chunk_dealloc_mmap(void *chunk, size_t size)
|
chunk_dealloc_mmap(void *chunk, size_t size)
|
||||||
{
|
{
|
||||||
|
|
||||||
pages_unmap(chunk, size);
|
pages_unmap(chunk, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
chunk_mmap_boot(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef NO_TLS
|
||||||
|
if (pthread_key_create(&mmap_unaligned_tsd, NULL) != 0) {
|
||||||
|
malloc_write("<jemalloc>: Error in pthread_key_create()\n");
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
@@ -184,6 +184,24 @@ chunk_dealloc_swap_record(void *chunk, size_t size)
|
|||||||
return (node);
|
return (node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
chunk_in_swap(void *chunk)
|
||||||
|
{
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
assert(swap_enabled);
|
||||||
|
|
||||||
|
malloc_mutex_lock(&swap_mtx);
|
||||||
|
if ((uintptr_t)chunk >= (uintptr_t)swap_base
|
||||||
|
&& (uintptr_t)chunk < (uintptr_t)swap_max)
|
||||||
|
ret = true;
|
||||||
|
else
|
||||||
|
ret = false;
|
||||||
|
malloc_mutex_unlock(&swap_mtx);
|
||||||
|
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
chunk_dealloc_swap(void *chunk, size_t size)
|
chunk_dealloc_swap(void *chunk, size_t size)
|
||||||
{
|
{
|
||||||
@@ -219,15 +237,15 @@ chunk_dealloc_swap(void *chunk, size_t size)
|
|||||||
} else
|
} else
|
||||||
madvise(chunk, size, MADV_DONTNEED);
|
madvise(chunk, size, MADV_DONTNEED);
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
swap_avail += size;
|
||||||
|
#endif
|
||||||
ret = false;
|
ret = false;
|
||||||
goto RETURN;
|
goto RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = true;
|
ret = true;
|
||||||
RETURN:
|
RETURN:
|
||||||
#ifdef JEMALLOC_STATS
|
|
||||||
swap_avail += size;
|
|
||||||
#endif
|
|
||||||
malloc_mutex_unlock(&swap_mtx);
|
malloc_mutex_unlock(&swap_mtx);
|
||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
@@ -283,7 +301,7 @@ chunk_swap_enable(const int *fds, unsigned nfds, bool prezeroed)
|
|||||||
* Allocate a chunk-aligned region of anonymous memory, which will
|
* Allocate a chunk-aligned region of anonymous memory, which will
|
||||||
* be the final location for the memory-mapped files.
|
* be the final location for the memory-mapped files.
|
||||||
*/
|
*/
|
||||||
vaddr = chunk_alloc_mmap(cumsize);
|
vaddr = chunk_alloc_mmap_noreserve(cumsize);
|
||||||
if (vaddr == NULL) {
|
if (vaddr == NULL) {
|
||||||
ret = true;
|
ret = true;
|
||||||
goto RETURN;
|
goto RETURN;
|
||||||
@@ -294,18 +312,21 @@ chunk_swap_enable(const int *fds, unsigned nfds, bool prezeroed)
|
|||||||
void *addr = mmap((void *)((uintptr_t)vaddr + voff), sizes[i],
|
void *addr = mmap((void *)((uintptr_t)vaddr + voff), sizes[i],
|
||||||
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fds[i], 0);
|
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fds[i], 0);
|
||||||
if (addr == MAP_FAILED) {
|
if (addr == MAP_FAILED) {
|
||||||
char buf[STRERROR_BUF];
|
char buf[BUFERROR_BUF];
|
||||||
|
|
||||||
strerror_r(errno, buf, sizeof(buf));
|
|
||||||
malloc_write4("<jemalloc>",
|
buferror(errno, buf, sizeof(buf));
|
||||||
": Error in mmap(..., MAP_FIXED, ...): ",
|
malloc_write(
|
||||||
buf, "\n");
|
"<jemalloc>: Error in mmap(..., MAP_FIXED, ...): ");
|
||||||
|
malloc_write(buf);
|
||||||
|
malloc_write("\n");
|
||||||
if (opt_abort)
|
if (opt_abort)
|
||||||
abort();
|
abort();
|
||||||
if (munmap(vaddr, voff) == -1) {
|
if (munmap(vaddr, voff) == -1) {
|
||||||
strerror_r(errno, buf, sizeof(buf));
|
buferror(errno, buf, sizeof(buf));
|
||||||
malloc_write4("<jemalloc>",
|
malloc_write("<jemalloc>: Error in munmap(): ");
|
||||||
": Error in munmap(): ", buf, "\n");
|
malloc_write(buf);
|
||||||
|
malloc_write("\n");
|
||||||
}
|
}
|
||||||
ret = true;
|
ret = true;
|
||||||
goto RETURN;
|
goto RETURN;
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
* respectively.
|
* respectively.
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
#define CKH_C_
|
#define JEMALLOC_CKH_C_
|
||||||
#include "jemalloc/internal/jemalloc_internal.h"
|
#include "jemalloc/internal/jemalloc_internal.h"
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@@ -73,7 +73,7 @@ ckh_isearch(ckh_t *ckh, const void *key)
|
|||||||
size_t hash1, hash2, bucket, cell;
|
size_t hash1, hash2, bucket, cell;
|
||||||
|
|
||||||
assert(ckh != NULL);
|
assert(ckh != NULL);
|
||||||
assert(ckh->magic = CKH_MAGIG);
|
dassert(ckh->magic == CKH_MAGIC);
|
||||||
|
|
||||||
ckh->hash(key, ckh->lg_curbuckets, &hash1, &hash2);
|
ckh->hash(key, ckh->lg_curbuckets, &hash1, &hash2);
|
||||||
|
|
||||||
@@ -262,14 +262,19 @@ ckh_grow(ckh_t *ckh)
|
|||||||
lg_prevbuckets = ckh->lg_curbuckets;
|
lg_prevbuckets = ckh->lg_curbuckets;
|
||||||
lg_curcells = ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS;
|
lg_curcells = ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
size_t usize;
|
||||||
|
|
||||||
lg_curcells++;
|
lg_curcells++;
|
||||||
tab = (ckhc_t *) ipalloc((ZU(1) << LG_CACHELINE),
|
usize = sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE, NULL);
|
||||||
sizeof(ckhc_t) << lg_curcells);
|
if (usize == 0) {
|
||||||
|
ret = true;
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
|
tab = (ckhc_t *)ipalloc(usize, CACHELINE, true);
|
||||||
if (tab == NULL) {
|
if (tab == NULL) {
|
||||||
ret = true;
|
ret = true;
|
||||||
goto RETURN;
|
goto RETURN;
|
||||||
}
|
}
|
||||||
memset(tab, 0, sizeof(ckhc_t) << lg_curcells);
|
|
||||||
/* Swap in new table. */
|
/* Swap in new table. */
|
||||||
ttab = ckh->tab;
|
ttab = ckh->tab;
|
||||||
ckh->tab = tab;
|
ckh->tab = tab;
|
||||||
@@ -296,7 +301,7 @@ static void
|
|||||||
ckh_shrink(ckh_t *ckh)
|
ckh_shrink(ckh_t *ckh)
|
||||||
{
|
{
|
||||||
ckhc_t *tab, *ttab;
|
ckhc_t *tab, *ttab;
|
||||||
size_t lg_curcells;
|
size_t lg_curcells, usize;
|
||||||
unsigned lg_prevbuckets;
|
unsigned lg_prevbuckets;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -305,8 +310,10 @@ ckh_shrink(ckh_t *ckh)
|
|||||||
*/
|
*/
|
||||||
lg_prevbuckets = ckh->lg_curbuckets;
|
lg_prevbuckets = ckh->lg_curbuckets;
|
||||||
lg_curcells = ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS - 1;
|
lg_curcells = ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS - 1;
|
||||||
tab = (ckhc_t *)ipalloc((ZU(1) << LG_CACHELINE),
|
usize = sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE, NULL);
|
||||||
sizeof(ckhc_t) << lg_curcells);
|
if (usize == 0)
|
||||||
|
return;
|
||||||
|
tab = (ckhc_t *)ipalloc(usize, CACHELINE, true);
|
||||||
if (tab == NULL) {
|
if (tab == NULL) {
|
||||||
/*
|
/*
|
||||||
* An OOM error isn't worth propagating, since it doesn't
|
* An OOM error isn't worth propagating, since it doesn't
|
||||||
@@ -314,7 +321,6 @@ ckh_shrink(ckh_t *ckh)
|
|||||||
*/
|
*/
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memset(tab, 0, sizeof(ckhc_t) << lg_curcells);
|
|
||||||
/* Swap in new table. */
|
/* Swap in new table. */
|
||||||
ttab = ckh->tab;
|
ttab = ckh->tab;
|
||||||
ckh->tab = tab;
|
ckh->tab = tab;
|
||||||
@@ -342,7 +348,7 @@ bool
|
|||||||
ckh_new(ckh_t *ckh, size_t minitems, ckh_hash_t *hash, ckh_keycomp_t *keycomp)
|
ckh_new(ckh_t *ckh, size_t minitems, ckh_hash_t *hash, ckh_keycomp_t *keycomp)
|
||||||
{
|
{
|
||||||
bool ret;
|
bool ret;
|
||||||
size_t mincells;
|
size_t mincells, usize;
|
||||||
unsigned lg_mincells;
|
unsigned lg_mincells;
|
||||||
|
|
||||||
assert(minitems > 0);
|
assert(minitems > 0);
|
||||||
@@ -377,16 +383,19 @@ ckh_new(ckh_t *ckh, size_t minitems, ckh_hash_t *hash, ckh_keycomp_t *keycomp)
|
|||||||
ckh->hash = hash;
|
ckh->hash = hash;
|
||||||
ckh->keycomp = keycomp;
|
ckh->keycomp = keycomp;
|
||||||
|
|
||||||
ckh->tab = (ckhc_t *)ipalloc((ZU(1) << LG_CACHELINE),
|
usize = sa2u(sizeof(ckhc_t) << lg_mincells, CACHELINE, NULL);
|
||||||
sizeof(ckhc_t) << lg_mincells);
|
if (usize == 0) {
|
||||||
|
ret = true;
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
|
ckh->tab = (ckhc_t *)ipalloc(usize, CACHELINE, true);
|
||||||
if (ckh->tab == NULL) {
|
if (ckh->tab == NULL) {
|
||||||
ret = true;
|
ret = true;
|
||||||
goto RETURN;
|
goto RETURN;
|
||||||
}
|
}
|
||||||
memset(ckh->tab, 0, sizeof(ckhc_t) << lg_mincells);
|
|
||||||
|
|
||||||
#ifdef JEMALLOC_DEBUG
|
#ifdef JEMALLOC_DEBUG
|
||||||
ckh->magic = CKH_MAGIG;
|
ckh->magic = CKH_MAGIC;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ret = false;
|
ret = false;
|
||||||
@@ -399,7 +408,7 @@ ckh_delete(ckh_t *ckh)
|
|||||||
{
|
{
|
||||||
|
|
||||||
assert(ckh != NULL);
|
assert(ckh != NULL);
|
||||||
assert(ckh->magic = CKH_MAGIG);
|
dassert(ckh->magic == CKH_MAGIC);
|
||||||
|
|
||||||
#ifdef CKH_VERBOSE
|
#ifdef CKH_VERBOSE
|
||||||
malloc_printf(
|
malloc_printf(
|
||||||
@@ -424,7 +433,7 @@ ckh_count(ckh_t *ckh)
|
|||||||
{
|
{
|
||||||
|
|
||||||
assert(ckh != NULL);
|
assert(ckh != NULL);
|
||||||
assert(ckh->magic = CKH_MAGIG);
|
dassert(ckh->magic == CKH_MAGIC);
|
||||||
|
|
||||||
return (ckh->count);
|
return (ckh->count);
|
||||||
}
|
}
|
||||||
@@ -455,7 +464,7 @@ ckh_insert(ckh_t *ckh, const void *key, const void *data)
|
|||||||
bool ret;
|
bool ret;
|
||||||
|
|
||||||
assert(ckh != NULL);
|
assert(ckh != NULL);
|
||||||
assert(ckh->magic = CKH_MAGIG);
|
dassert(ckh->magic == CKH_MAGIC);
|
||||||
assert(ckh_search(ckh, key, NULL, NULL));
|
assert(ckh_search(ckh, key, NULL, NULL));
|
||||||
|
|
||||||
#ifdef CKH_COUNT
|
#ifdef CKH_COUNT
|
||||||
@@ -480,7 +489,7 @@ ckh_remove(ckh_t *ckh, const void *searchkey, void **key, void **data)
|
|||||||
size_t cell;
|
size_t cell;
|
||||||
|
|
||||||
assert(ckh != NULL);
|
assert(ckh != NULL);
|
||||||
assert(ckh->magic = CKH_MAGIG);
|
dassert(ckh->magic == CKH_MAGIC);
|
||||||
|
|
||||||
cell = ckh_isearch(ckh, searchkey);
|
cell = ckh_isearch(ckh, searchkey);
|
||||||
if (cell != SIZE_T_MAX) {
|
if (cell != SIZE_T_MAX) {
|
||||||
@@ -512,7 +521,7 @@ ckh_search(ckh_t *ckh, const void *searchkey, void **key, void **data)
|
|||||||
size_t cell;
|
size_t cell;
|
||||||
|
|
||||||
assert(ckh != NULL);
|
assert(ckh != NULL);
|
||||||
assert(ckh->magic = CKH_MAGIG);
|
dassert(ckh->magic == CKH_MAGIC);
|
||||||
|
|
||||||
cell = ckh_isearch(ckh, searchkey);
|
cell = ckh_isearch(ckh, searchkey);
|
||||||
if (cell != SIZE_T_MAX) {
|
if (cell != SIZE_T_MAX) {
|
||||||
@@ -547,7 +556,7 @@ ckh_string_hash(const void *key, unsigned minbits, size_t *hash1, size_t *hash2)
|
|||||||
} else {
|
} else {
|
||||||
ret1 = h;
|
ret1 = h;
|
||||||
ret2 = hash(key, strlen((const char *)key),
|
ret2 = hash(key, strlen((const char *)key),
|
||||||
0x8432a476666bbc13U);
|
0x8432a476666bbc13LLU);
|
||||||
}
|
}
|
||||||
|
|
||||||
*hash1 = ret1;
|
*hash1 = ret1;
|
||||||
@@ -570,12 +579,21 @@ ckh_pointer_hash(const void *key, unsigned minbits, size_t *hash1,
|
|||||||
{
|
{
|
||||||
size_t ret1, ret2;
|
size_t ret1, ret2;
|
||||||
uint64_t h;
|
uint64_t h;
|
||||||
|
union {
|
||||||
|
const void *v;
|
||||||
|
uint64_t i;
|
||||||
|
} u;
|
||||||
|
|
||||||
assert(minbits <= 32 || (SIZEOF_PTR == 8 && minbits <= 64));
|
assert(minbits <= 32 || (SIZEOF_PTR == 8 && minbits <= 64));
|
||||||
assert(hash1 != NULL);
|
assert(hash1 != NULL);
|
||||||
assert(hash2 != NULL);
|
assert(hash2 != NULL);
|
||||||
|
|
||||||
h = hash(&key, sizeof(void *), 0xd983396e68886082LLU);
|
assert(sizeof(u.v) == sizeof(u.i));
|
||||||
|
#if (LG_SIZEOF_PTR != LG_SIZEOF_INT)
|
||||||
|
u.i = 0;
|
||||||
|
#endif
|
||||||
|
u.v = key;
|
||||||
|
h = hash(&u.i, sizeof(u.i), 0xd983396e68886082LLU);
|
||||||
if (minbits <= 32) {
|
if (minbits <= 32) {
|
||||||
/*
|
/*
|
||||||
* Avoid doing multiple hashes, since a single hash provides
|
* Avoid doing multiple hashes, since a single hash provides
|
||||||
@@ -586,7 +604,7 @@ ckh_pointer_hash(const void *key, unsigned minbits, size_t *hash1,
|
|||||||
} else {
|
} else {
|
||||||
assert(SIZEOF_PTR == 8);
|
assert(SIZEOF_PTR == 8);
|
||||||
ret1 = h;
|
ret1 = h;
|
||||||
ret2 = hash(&key, sizeof(void *), 0x5e2be9aff8709a5dLLU);
|
ret2 = hash(&u.i, sizeof(u.i), 0x5e2be9aff8709a5dLLU);
|
||||||
}
|
}
|
||||||
|
|
||||||
*hash1 = ret1;
|
*hash1 = ret1;
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,2 +1,2 @@
|
|||||||
#define HASH_C_
|
#define JEMALLOC_HASH_C_
|
||||||
#include "jemalloc/internal/jemalloc_internal.h"
|
#include "jemalloc/internal/jemalloc_internal.h"
|
||||||
@@ -37,7 +37,7 @@ huge_malloc(size_t size, bool zero)
|
|||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
ret = chunk_alloc(csize, &zero);
|
ret = chunk_alloc(csize, false, &zero);
|
||||||
if (ret == NULL) {
|
if (ret == NULL) {
|
||||||
base_node_dealloc(node);
|
base_node_dealloc(node);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
@@ -50,6 +50,7 @@ huge_malloc(size_t size, bool zero)
|
|||||||
malloc_mutex_lock(&huge_mtx);
|
malloc_mutex_lock(&huge_mtx);
|
||||||
extent_tree_ad_insert(&huge, node);
|
extent_tree_ad_insert(&huge, node);
|
||||||
#ifdef JEMALLOC_STATS
|
#ifdef JEMALLOC_STATS
|
||||||
|
stats_cactive_add(csize);
|
||||||
huge_nmalloc++;
|
huge_nmalloc++;
|
||||||
huge_allocated += csize;
|
huge_allocated += csize;
|
||||||
#endif
|
#endif
|
||||||
@@ -69,12 +70,11 @@ huge_malloc(size_t size, bool zero)
|
|||||||
|
|
||||||
/* Only handles large allocations that require more than chunk alignment. */
|
/* Only handles large allocations that require more than chunk alignment. */
|
||||||
void *
|
void *
|
||||||
huge_palloc(size_t alignment, size_t size)
|
huge_palloc(size_t size, size_t alignment, bool zero)
|
||||||
{
|
{
|
||||||
void *ret;
|
void *ret;
|
||||||
size_t alloc_size, chunk_size, offset;
|
size_t alloc_size, chunk_size, offset;
|
||||||
extent_node_t *node;
|
extent_node_t *node;
|
||||||
bool zero;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This allocation requires alignment that is even larger than chunk
|
* This allocation requires alignment that is even larger than chunk
|
||||||
@@ -84,7 +84,7 @@ huge_palloc(size_t alignment, size_t size)
|
|||||||
* alignment, in order to assure the alignment can be achieved, then
|
* alignment, in order to assure the alignment can be achieved, then
|
||||||
* unmap leading and trailing chunks.
|
* unmap leading and trailing chunks.
|
||||||
*/
|
*/
|
||||||
assert(alignment >= chunksize);
|
assert(alignment > chunksize);
|
||||||
|
|
||||||
chunk_size = CHUNK_CEILING(size);
|
chunk_size = CHUNK_CEILING(size);
|
||||||
|
|
||||||
@@ -98,8 +98,7 @@ huge_palloc(size_t alignment, size_t size)
|
|||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
zero = false;
|
ret = chunk_alloc(alloc_size, false, &zero);
|
||||||
ret = chunk_alloc(alloc_size, &zero);
|
|
||||||
if (ret == NULL) {
|
if (ret == NULL) {
|
||||||
base_node_dealloc(node);
|
base_node_dealloc(node);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
@@ -136,59 +135,138 @@ huge_palloc(size_t alignment, size_t size)
|
|||||||
malloc_mutex_lock(&huge_mtx);
|
malloc_mutex_lock(&huge_mtx);
|
||||||
extent_tree_ad_insert(&huge, node);
|
extent_tree_ad_insert(&huge, node);
|
||||||
#ifdef JEMALLOC_STATS
|
#ifdef JEMALLOC_STATS
|
||||||
|
stats_cactive_add(chunk_size);
|
||||||
huge_nmalloc++;
|
huge_nmalloc++;
|
||||||
huge_allocated += chunk_size;
|
huge_allocated += chunk_size;
|
||||||
#endif
|
#endif
|
||||||
malloc_mutex_unlock(&huge_mtx);
|
malloc_mutex_unlock(&huge_mtx);
|
||||||
|
|
||||||
#ifdef JEMALLOC_FILL
|
#ifdef JEMALLOC_FILL
|
||||||
if (opt_junk)
|
if (zero == false) {
|
||||||
memset(ret, 0xa5, chunk_size);
|
if (opt_junk)
|
||||||
else if (opt_zero)
|
memset(ret, 0xa5, chunk_size);
|
||||||
memset(ret, 0, chunk_size);
|
else if (opt_zero)
|
||||||
|
memset(ret, 0, chunk_size);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
huge_ralloc(void *ptr, size_t size, size_t oldsize)
|
huge_ralloc_no_move(void *ptr, size_t oldsize, size_t size, size_t extra)
|
||||||
{
|
{
|
||||||
void *ret;
|
|
||||||
size_t copysize;
|
|
||||||
|
|
||||||
/* Avoid moving the allocation if the size class would not change. */
|
/*
|
||||||
if (oldsize > arena_maxclass &&
|
* Avoid moving the allocation if the size class can be left the same.
|
||||||
CHUNK_CEILING(size) == CHUNK_CEILING(oldsize)) {
|
*/
|
||||||
|
if (oldsize > arena_maxclass
|
||||||
|
&& CHUNK_CEILING(oldsize) >= CHUNK_CEILING(size)
|
||||||
|
&& CHUNK_CEILING(oldsize) <= CHUNK_CEILING(size+extra)) {
|
||||||
|
assert(CHUNK_CEILING(oldsize) == oldsize);
|
||||||
#ifdef JEMALLOC_FILL
|
#ifdef JEMALLOC_FILL
|
||||||
if (opt_junk && size < oldsize) {
|
if (opt_junk && size < oldsize) {
|
||||||
memset((void *)((uintptr_t)ptr + size), 0x5a, oldsize
|
memset((void *)((uintptr_t)ptr + size), 0x5a,
|
||||||
- size);
|
oldsize - size);
|
||||||
} else if (opt_zero && size > oldsize) {
|
|
||||||
memset((void *)((uintptr_t)ptr + oldsize), 0, size
|
|
||||||
- oldsize);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return (ptr);
|
return (ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Reallocation would require a move. */
|
||||||
* If we get here, then size and oldsize are different enough that we
|
return (NULL);
|
||||||
* need to use a different size class. In that case, fall back to
|
}
|
||||||
* allocating new space and copying.
|
|
||||||
*/
|
|
||||||
ret = huge_malloc(size, false);
|
|
||||||
if (ret == NULL)
|
|
||||||
return (NULL);
|
|
||||||
|
|
||||||
|
void *
|
||||||
|
huge_ralloc(void *ptr, size_t oldsize, size_t size, size_t extra,
|
||||||
|
size_t alignment, bool zero)
|
||||||
|
{
|
||||||
|
void *ret;
|
||||||
|
size_t copysize;
|
||||||
|
|
||||||
|
/* Try to avoid moving the allocation. */
|
||||||
|
ret = huge_ralloc_no_move(ptr, oldsize, size, extra);
|
||||||
|
if (ret != NULL)
|
||||||
|
return (ret);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* size and oldsize are different enough that we need to use a
|
||||||
|
* different size class. In that case, fall back to allocating new
|
||||||
|
* space and copying.
|
||||||
|
*/
|
||||||
|
if (alignment > chunksize)
|
||||||
|
ret = huge_palloc(size + extra, alignment, zero);
|
||||||
|
else
|
||||||
|
ret = huge_malloc(size + extra, zero);
|
||||||
|
|
||||||
|
if (ret == NULL) {
|
||||||
|
if (extra == 0)
|
||||||
|
return (NULL);
|
||||||
|
/* Try again, this time without extra. */
|
||||||
|
if (alignment > chunksize)
|
||||||
|
ret = huge_palloc(size, alignment, zero);
|
||||||
|
else
|
||||||
|
ret = huge_malloc(size, zero);
|
||||||
|
|
||||||
|
if (ret == 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;
|
copysize = (size < oldsize) ? size : oldsize;
|
||||||
memcpy(ret, ptr, copysize);
|
|
||||||
idalloc(ptr);
|
/*
|
||||||
|
* Use mremap(2) if this is a huge-->huge reallocation, and neither the
|
||||||
|
* source nor the destination are in swap or dss.
|
||||||
|
*/
|
||||||
|
#ifdef JEMALLOC_MREMAP_FIXED
|
||||||
|
if (oldsize >= chunksize
|
||||||
|
# ifdef JEMALLOC_SWAP
|
||||||
|
&& (swap_enabled == false || (chunk_in_swap(ptr) == false &&
|
||||||
|
chunk_in_swap(ret) == false))
|
||||||
|
# endif
|
||||||
|
# ifdef JEMALLOC_DSS
|
||||||
|
&& chunk_in_dss(ptr) == false && chunk_in_dss(ret) == false
|
||||||
|
# endif
|
||||||
|
) {
|
||||||
|
size_t newsize = huge_salloc(ret);
|
||||||
|
|
||||||
|
if (mremap(ptr, oldsize, newsize, MREMAP_MAYMOVE|MREMAP_FIXED,
|
||||||
|
ret) == MAP_FAILED) {
|
||||||
|
/*
|
||||||
|
* Assuming no chunk management bugs in the allocator,
|
||||||
|
* the only documented way an error can occur here is
|
||||||
|
* if the application changed the map type for a
|
||||||
|
* portion of the old allocation. This is firmly in
|
||||||
|
* undefined behavior territory, so write a diagnostic
|
||||||
|
* message, and optionally abort.
|
||||||
|
*/
|
||||||
|
char buf[BUFERROR_BUF];
|
||||||
|
|
||||||
|
buferror(errno, buf, sizeof(buf));
|
||||||
|
malloc_write("<jemalloc>: Error in mremap(): ");
|
||||||
|
malloc_write(buf);
|
||||||
|
malloc_write("\n");
|
||||||
|
if (opt_abort)
|
||||||
|
abort();
|
||||||
|
memcpy(ret, ptr, copysize);
|
||||||
|
idalloc(ptr);
|
||||||
|
} else
|
||||||
|
huge_dalloc(ptr, false);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
memcpy(ret, ptr, copysize);
|
||||||
|
idalloc(ptr);
|
||||||
|
}
|
||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
huge_dalloc(void *ptr)
|
huge_dalloc(void *ptr, bool unmap)
|
||||||
{
|
{
|
||||||
extent_node_t *node, key;
|
extent_node_t *node, key;
|
||||||
|
|
||||||
@@ -202,20 +280,23 @@ huge_dalloc(void *ptr)
|
|||||||
extent_tree_ad_remove(&huge, node);
|
extent_tree_ad_remove(&huge, node);
|
||||||
|
|
||||||
#ifdef JEMALLOC_STATS
|
#ifdef JEMALLOC_STATS
|
||||||
|
stats_cactive_sub(node->size);
|
||||||
huge_ndalloc++;
|
huge_ndalloc++;
|
||||||
huge_allocated -= node->size;
|
huge_allocated -= node->size;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
malloc_mutex_unlock(&huge_mtx);
|
malloc_mutex_unlock(&huge_mtx);
|
||||||
|
|
||||||
|
if (unmap) {
|
||||||
/* Unmap chunk. */
|
/* Unmap chunk. */
|
||||||
#ifdef JEMALLOC_FILL
|
#ifdef JEMALLOC_FILL
|
||||||
#if (defined(JEMALLOC_SWAP) || defined(JEMALLOC_DSS))
|
#if (defined(JEMALLOC_SWAP) || defined(JEMALLOC_DSS))
|
||||||
if (opt_junk)
|
if (opt_junk)
|
||||||
memset(node->addr, 0x5a, node->size);
|
memset(node->addr, 0x5a, node->size);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
chunk_dealloc(node->addr, node->size);
|
chunk_dealloc(node->addr, node->size);
|
||||||
|
}
|
||||||
|
|
||||||
base_node_dealloc(node);
|
base_node_dealloc(node);
|
||||||
}
|
}
|
||||||
@@ -241,10 +322,10 @@ huge_salloc(const void *ptr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JEMALLOC_PROF
|
#ifdef JEMALLOC_PROF
|
||||||
prof_thr_cnt_t *
|
prof_ctx_t *
|
||||||
huge_prof_cnt_get(const void *ptr)
|
huge_prof_ctx_get(const void *ptr)
|
||||||
{
|
{
|
||||||
prof_thr_cnt_t *ret;
|
prof_ctx_t *ret;
|
||||||
extent_node_t *node, key;
|
extent_node_t *node, key;
|
||||||
|
|
||||||
malloc_mutex_lock(&huge_mtx);
|
malloc_mutex_lock(&huge_mtx);
|
||||||
@@ -254,7 +335,7 @@ huge_prof_cnt_get(const void *ptr)
|
|||||||
node = extent_tree_ad_search(&huge, &key);
|
node = extent_tree_ad_search(&huge, &key);
|
||||||
assert(node != NULL);
|
assert(node != NULL);
|
||||||
|
|
||||||
ret = node->prof_cnt;
|
ret = node->prof_ctx;
|
||||||
|
|
||||||
malloc_mutex_unlock(&huge_mtx);
|
malloc_mutex_unlock(&huge_mtx);
|
||||||
|
|
||||||
@@ -262,7 +343,7 @@ huge_prof_cnt_get(const void *ptr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
huge_prof_cnt_set(const void *ptr, prof_thr_cnt_t *cnt)
|
huge_prof_ctx_set(const void *ptr, prof_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
extent_node_t *node, key;
|
extent_node_t *node, key;
|
||||||
|
|
||||||
@@ -273,7 +354,7 @@ huge_prof_cnt_set(const void *ptr, prof_thr_cnt_t *cnt)
|
|||||||
node = extent_tree_ad_search(&huge, &key);
|
node = extent_tree_ad_search(&huge, &key);
|
||||||
assert(node != NULL);
|
assert(node != NULL);
|
||||||
|
|
||||||
node->prof_cnt = cnt;
|
node->prof_ctx = ctx;
|
||||||
|
|
||||||
malloc_mutex_unlock(&huge_mtx);
|
malloc_mutex_unlock(&huge_mtx);
|
||||||
}
|
}
|
||||||
1847
src/jemalloc.c
Normal file
1847
src/jemalloc.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,2 +1,2 @@
|
|||||||
#define MB_C_
|
#define JEMALLOC_MB_C_
|
||||||
#include "jemalloc/internal/jemalloc_internal.h"
|
#include "jemalloc/internal/jemalloc_internal.h"
|
||||||
@@ -28,9 +28,8 @@ pthread_create_once(void)
|
|||||||
|
|
||||||
pthread_create_fptr = dlsym(RTLD_NEXT, "pthread_create");
|
pthread_create_fptr = dlsym(RTLD_NEXT, "pthread_create");
|
||||||
if (pthread_create_fptr == NULL) {
|
if (pthread_create_fptr == NULL) {
|
||||||
malloc_write4("<jemalloc>",
|
malloc_write("<jemalloc>: Error in dlsym(RTLD_NEXT, "
|
||||||
": Error in dlsym(RTLD_NEXT, \"pthread_create\")\n", "",
|
"\"pthread_create\")\n");
|
||||||
"");
|
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,16 +55,36 @@ pthread_create(pthread_t *__restrict thread,
|
|||||||
bool
|
bool
|
||||||
malloc_mutex_init(malloc_mutex_t *mutex)
|
malloc_mutex_init(malloc_mutex_t *mutex)
|
||||||
{
|
{
|
||||||
|
#ifdef JEMALLOC_OSSPIN
|
||||||
|
*mutex = 0;
|
||||||
|
#else
|
||||||
pthread_mutexattr_t attr;
|
pthread_mutexattr_t attr;
|
||||||
|
|
||||||
if (pthread_mutexattr_init(&attr) != 0)
|
if (pthread_mutexattr_init(&attr) != 0)
|
||||||
return (true);
|
return (true);
|
||||||
|
#ifdef PTHREAD_MUTEX_ADAPTIVE_NP
|
||||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
|
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
|
||||||
|
#else
|
||||||
|
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
|
||||||
|
#endif
|
||||||
if (pthread_mutex_init(mutex, &attr) != 0) {
|
if (pthread_mutex_init(mutex, &attr) != 0) {
|
||||||
pthread_mutexattr_destroy(&attr);
|
pthread_mutexattr_destroy(&attr);
|
||||||
return (true);
|
return (true);
|
||||||
}
|
}
|
||||||
pthread_mutexattr_destroy(&attr);
|
pthread_mutexattr_destroy(&attr);
|
||||||
|
|
||||||
|
#endif
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
malloc_mutex_destroy(malloc_mutex_t *mutex)
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifndef JEMALLOC_OSSPIN
|
||||||
|
if (pthread_mutex_destroy(mutex) != 0) {
|
||||||
|
malloc_write("<jemalloc>: Error in pthread_mutex_destroy()\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
46
src/rtree.c
Normal file
46
src/rtree.c
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#define JEMALLOC_RTREE_C_
|
||||||
|
#include "jemalloc/internal/jemalloc_internal.h"
|
||||||
|
|
||||||
|
rtree_t *
|
||||||
|
rtree_new(unsigned bits)
|
||||||
|
{
|
||||||
|
rtree_t *ret;
|
||||||
|
unsigned bits_per_level, height, i;
|
||||||
|
|
||||||
|
bits_per_level = ffs(pow2_ceil((RTREE_NODESIZE / sizeof(void *)))) - 1;
|
||||||
|
height = bits / bits_per_level;
|
||||||
|
if (height * bits_per_level != bits)
|
||||||
|
height++;
|
||||||
|
assert(height * bits_per_level >= bits);
|
||||||
|
|
||||||
|
ret = (rtree_t*)base_alloc(offsetof(rtree_t, level2bits) +
|
||||||
|
(sizeof(unsigned) * height));
|
||||||
|
if (ret == NULL)
|
||||||
|
return (NULL);
|
||||||
|
memset(ret, 0, offsetof(rtree_t, level2bits) + (sizeof(unsigned) *
|
||||||
|
height));
|
||||||
|
|
||||||
|
if (malloc_mutex_init(&ret->mutex)) {
|
||||||
|
/* Leak the rtree. */
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
ret->height = height;
|
||||||
|
if (bits_per_level * height > bits)
|
||||||
|
ret->level2bits[0] = bits % bits_per_level;
|
||||||
|
else
|
||||||
|
ret->level2bits[0] = bits_per_level;
|
||||||
|
for (i = 1; i < height; i++)
|
||||||
|
ret->level2bits[i] = bits_per_level;
|
||||||
|
|
||||||
|
ret->root = (void**)base_alloc(sizeof(void *) << ret->level2bits[0]);
|
||||||
|
if (ret->root == NULL) {
|
||||||
|
/*
|
||||||
|
* We leak the rtree here, since there's no generic base
|
||||||
|
* deallocation.
|
||||||
|
*/
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
memset(ret->root, 0, sizeof(void *) << ret->level2bits[0]);
|
||||||
|
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
790
src/stats.c
Normal file
790
src/stats.c
Normal file
@@ -0,0 +1,790 @@
|
|||||||
|
#define JEMALLOC_STATS_C_
|
||||||
|
#include "jemalloc/internal/jemalloc_internal.h"
|
||||||
|
|
||||||
|
#define CTL_GET(n, v, t) do { \
|
||||||
|
size_t sz = sizeof(t); \
|
||||||
|
xmallctl(n, v, &sz, NULL, 0); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CTL_I_GET(n, v, t) do { \
|
||||||
|
size_t mib[6]; \
|
||||||
|
size_t miblen = sizeof(mib) / sizeof(size_t); \
|
||||||
|
size_t sz = sizeof(t); \
|
||||||
|
xmallctlnametomib(n, mib, &miblen); \
|
||||||
|
mib[2] = i; \
|
||||||
|
xmallctlbymib(mib, miblen, v, &sz, NULL, 0); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CTL_J_GET(n, v, t) do { \
|
||||||
|
size_t mib[6]; \
|
||||||
|
size_t miblen = sizeof(mib) / sizeof(size_t); \
|
||||||
|
size_t sz = sizeof(t); \
|
||||||
|
xmallctlnametomib(n, mib, &miblen); \
|
||||||
|
mib[2] = j; \
|
||||||
|
xmallctlbymib(mib, miblen, v, &sz, NULL, 0); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CTL_IJ_GET(n, v, t) do { \
|
||||||
|
size_t mib[6]; \
|
||||||
|
size_t miblen = sizeof(mib) / sizeof(size_t); \
|
||||||
|
size_t sz = sizeof(t); \
|
||||||
|
xmallctlnametomib(n, mib, &miblen); \
|
||||||
|
mib[2] = i; \
|
||||||
|
mib[4] = j; \
|
||||||
|
xmallctlbymib(mib, miblen, v, &sz, NULL, 0); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/* Data. */
|
||||||
|
|
||||||
|
bool opt_stats_print = false;
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
size_t stats_cactive = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/* Function prototypes for non-inline static functions. */
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
static void malloc_vcprintf(void (*write_cb)(void *, const char *),
|
||||||
|
void *cbopaque, const char *format, va_list ap);
|
||||||
|
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_print(void (*write_cb)(void *, const char *),
|
||||||
|
void *cbopaque, unsigned i);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We don't want to depend on vsnprintf() for production builds, since that can
|
||||||
|
* cause unnecessary bloat for static binaries. u2s() provides minimal integer
|
||||||
|
* printing functionality, so that malloc_printf() use can be limited to
|
||||||
|
* JEMALLOC_STATS code.
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
u2s(uint64_t x, unsigned base, char *s)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
i = UMAX2S_BUFSIZE - 1;
|
||||||
|
s[i] = '\0';
|
||||||
|
switch (base) {
|
||||||
|
case 10:
|
||||||
|
do {
|
||||||
|
i--;
|
||||||
|
s[i] = "0123456789"[x % (uint64_t)10];
|
||||||
|
x /= (uint64_t)10;
|
||||||
|
} while (x > 0);
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
do {
|
||||||
|
i--;
|
||||||
|
s[i] = "0123456789abcdef"[x & 0xf];
|
||||||
|
x >>= 4;
|
||||||
|
} while (x > 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
do {
|
||||||
|
i--;
|
||||||
|
s[i] = "0123456789abcdefghijklmnopqrstuvwxyz"[x %
|
||||||
|
(uint64_t)base];
|
||||||
|
x /= (uint64_t)base;
|
||||||
|
} while (x > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (&s[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
static void
|
||||||
|
malloc_vcprintf(void (*write_cb)(void *, const char *), void *cbopaque,
|
||||||
|
const char *format, va_list ap)
|
||||||
|
{
|
||||||
|
char buf[4096];
|
||||||
|
|
||||||
|
if (write_cb == NULL) {
|
||||||
|
/*
|
||||||
|
* The caller did not provide an alternate write_cb callback
|
||||||
|
* function, so use the default one. malloc_write() is an
|
||||||
|
* inline function, so use malloc_message() directly here.
|
||||||
|
*/
|
||||||
|
write_cb = JEMALLOC_P(malloc_message);
|
||||||
|
cbopaque = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
vsnprintf(buf, sizeof(buf), format, ap);
|
||||||
|
write_cb(cbopaque, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print to a callback function in such a way as to (hopefully) avoid memory
|
||||||
|
* allocation.
|
||||||
|
*/
|
||||||
|
JEMALLOC_ATTR(format(printf, 3, 4))
|
||||||
|
void
|
||||||
|
malloc_cprintf(void (*write_cb)(void *, const char *), void *cbopaque,
|
||||||
|
const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
malloc_vcprintf(write_cb, cbopaque, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print to stderr in such a way as to (hopefully) avoid memory allocation.
|
||||||
|
*/
|
||||||
|
JEMALLOC_ATTR(format(printf, 1, 2))
|
||||||
|
void
|
||||||
|
malloc_printf(const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
malloc_vcprintf(NULL, NULL, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
static void
|
||||||
|
stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque,
|
||||||
|
unsigned i)
|
||||||
|
{
|
||||||
|
size_t pagesize;
|
||||||
|
bool config_tcache;
|
||||||
|
unsigned nbins, j, gap_start;
|
||||||
|
|
||||||
|
CTL_GET("arenas.pagesize", &pagesize, size_t);
|
||||||
|
|
||||||
|
CTL_GET("config.tcache", &config_tcache, bool);
|
||||||
|
if (config_tcache) {
|
||||||
|
malloc_cprintf(write_cb, cbopaque,
|
||||||
|
"bins: bin size regs pgs allocated nmalloc"
|
||||||
|
" ndalloc nrequests nfills nflushes"
|
||||||
|
" newruns reruns maxruns curruns\n");
|
||||||
|
} else {
|
||||||
|
malloc_cprintf(write_cb, cbopaque,
|
||||||
|
"bins: bin size regs pgs allocated nmalloc"
|
||||||
|
" ndalloc newruns reruns maxruns"
|
||||||
|
" curruns\n");
|
||||||
|
}
|
||||||
|
CTL_GET("arenas.nbins", &nbins, unsigned);
|
||||||
|
for (j = 0, gap_start = UINT_MAX; j < nbins; j++) {
|
||||||
|
uint64_t nruns;
|
||||||
|
|
||||||
|
CTL_IJ_GET("stats.arenas.0.bins.0.nruns", &nruns, uint64_t);
|
||||||
|
if (nruns == 0) {
|
||||||
|
if (gap_start == UINT_MAX)
|
||||||
|
gap_start = j;
|
||||||
|
} else {
|
||||||
|
unsigned ntbins_, nqbins, ncbins, nsbins;
|
||||||
|
size_t reg_size, run_size, allocated;
|
||||||
|
uint32_t nregs;
|
||||||
|
uint64_t nmalloc, ndalloc, nrequests, nfills, nflushes;
|
||||||
|
uint64_t reruns;
|
||||||
|
size_t highruns, curruns;
|
||||||
|
|
||||||
|
if (gap_start != UINT_MAX) {
|
||||||
|
if (j > gap_start + 1) {
|
||||||
|
/* Gap of more than one size class. */
|
||||||
|
malloc_cprintf(write_cb, cbopaque,
|
||||||
|
"[%u..%u]\n", gap_start,
|
||||||
|
j - 1);
|
||||||
|
} else {
|
||||||
|
/* Gap of one size class. */
|
||||||
|
malloc_cprintf(write_cb, cbopaque,
|
||||||
|
"[%u]\n", gap_start);
|
||||||
|
}
|
||||||
|
gap_start = UINT_MAX;
|
||||||
|
}
|
||||||
|
CTL_GET("arenas.ntbins", &ntbins_, unsigned);
|
||||||
|
CTL_GET("arenas.nqbins", &nqbins, unsigned);
|
||||||
|
CTL_GET("arenas.ncbins", &ncbins, unsigned);
|
||||||
|
CTL_GET("arenas.nsbins", &nsbins, unsigned);
|
||||||
|
CTL_J_GET("arenas.bin.0.size", ®_size, size_t);
|
||||||
|
CTL_J_GET("arenas.bin.0.nregs", &nregs, uint32_t);
|
||||||
|
CTL_J_GET("arenas.bin.0.run_size", &run_size, size_t);
|
||||||
|
CTL_IJ_GET("stats.arenas.0.bins.0.allocated",
|
||||||
|
&allocated, size_t);
|
||||||
|
CTL_IJ_GET("stats.arenas.0.bins.0.nmalloc",
|
||||||
|
&nmalloc, uint64_t);
|
||||||
|
CTL_IJ_GET("stats.arenas.0.bins.0.ndalloc",
|
||||||
|
&ndalloc, uint64_t);
|
||||||
|
if (config_tcache) {
|
||||||
|
CTL_IJ_GET("stats.arenas.0.bins.0.nrequests",
|
||||||
|
&nrequests, uint64_t);
|
||||||
|
CTL_IJ_GET("stats.arenas.0.bins.0.nfills",
|
||||||
|
&nfills, uint64_t);
|
||||||
|
CTL_IJ_GET("stats.arenas.0.bins.0.nflushes",
|
||||||
|
&nflushes, uint64_t);
|
||||||
|
}
|
||||||
|
CTL_IJ_GET("stats.arenas.0.bins.0.nreruns", &reruns,
|
||||||
|
uint64_t);
|
||||||
|
CTL_IJ_GET("stats.arenas.0.bins.0.highruns", &highruns,
|
||||||
|
size_t);
|
||||||
|
CTL_IJ_GET("stats.arenas.0.bins.0.curruns", &curruns,
|
||||||
|
size_t);
|
||||||
|
if (config_tcache) {
|
||||||
|
malloc_cprintf(write_cb, cbopaque,
|
||||||
|
"%13u %1s %5zu %4u %3zu %12zu %12"PRIu64
|
||||||
|
" %12"PRIu64" %12"PRIu64" %12"PRIu64
|
||||||
|
" %12"PRIu64" %12"PRIu64" %12"PRIu64
|
||||||
|
" %12zu %12zu\n",
|
||||||
|
j,
|
||||||
|
j < ntbins_ ? "T" : j < ntbins_ + nqbins ?
|
||||||
|
"Q" : j < ntbins_ + nqbins + ncbins ? "C" :
|
||||||
|
"S",
|
||||||
|
reg_size, nregs, run_size / pagesize,
|
||||||
|
allocated, nmalloc, ndalloc, nrequests,
|
||||||
|
nfills, nflushes, nruns, reruns, highruns,
|
||||||
|
curruns);
|
||||||
|
} else {
|
||||||
|
malloc_cprintf(write_cb, cbopaque,
|
||||||
|
"%13u %1s %5zu %4u %3zu %12zu %12"PRIu64
|
||||||
|
" %12"PRIu64" %12"PRIu64" %12"PRIu64
|
||||||
|
" %12zu %12zu\n",
|
||||||
|
j,
|
||||||
|
j < ntbins_ ? "T" : j < ntbins_ + nqbins ?
|
||||||
|
"Q" : j < ntbins_ + nqbins + ncbins ? "C" :
|
||||||
|
"S",
|
||||||
|
reg_size, nregs, run_size / pagesize,
|
||||||
|
allocated, nmalloc, ndalloc, nruns, reruns,
|
||||||
|
highruns, curruns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (gap_start != UINT_MAX) {
|
||||||
|
if (j > gap_start + 1) {
|
||||||
|
/* Gap of more than one size class. */
|
||||||
|
malloc_cprintf(write_cb, cbopaque, "[%u..%u]\n",
|
||||||
|
gap_start, j - 1);
|
||||||
|
} else {
|
||||||
|
/* Gap of one size class. */
|
||||||
|
malloc_cprintf(write_cb, cbopaque, "[%u]\n", gap_start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
stats_arena_lruns_print(void (*write_cb)(void *, const char *), void *cbopaque,
|
||||||
|
unsigned i)
|
||||||
|
{
|
||||||
|
size_t pagesize, nlruns, j;
|
||||||
|
ssize_t gap_start;
|
||||||
|
|
||||||
|
CTL_GET("arenas.pagesize", &pagesize, size_t);
|
||||||
|
|
||||||
|
malloc_cprintf(write_cb, cbopaque,
|
||||||
|
"large: size pages nmalloc ndalloc nrequests"
|
||||||
|
" maxruns curruns\n");
|
||||||
|
CTL_GET("arenas.nlruns", &nlruns, size_t);
|
||||||
|
for (j = 0, gap_start = -1; j < nlruns; j++) {
|
||||||
|
uint64_t nmalloc, ndalloc, nrequests;
|
||||||
|
size_t run_size, highruns, curruns;
|
||||||
|
|
||||||
|
CTL_IJ_GET("stats.arenas.0.lruns.0.nmalloc", &nmalloc,
|
||||||
|
uint64_t);
|
||||||
|
CTL_IJ_GET("stats.arenas.0.lruns.0.ndalloc", &ndalloc,
|
||||||
|
uint64_t);
|
||||||
|
CTL_IJ_GET("stats.arenas.0.lruns.0.nrequests", &nrequests,
|
||||||
|
uint64_t);
|
||||||
|
if (nrequests == 0) {
|
||||||
|
if (gap_start == -1)
|
||||||
|
gap_start = j;
|
||||||
|
} else {
|
||||||
|
CTL_J_GET("arenas.lrun.0.size", &run_size, size_t);
|
||||||
|
CTL_IJ_GET("stats.arenas.0.lruns.0.highruns", &highruns,
|
||||||
|
size_t);
|
||||||
|
CTL_IJ_GET("stats.arenas.0.lruns.0.curruns", &curruns,
|
||||||
|
size_t);
|
||||||
|
if (gap_start != -1) {
|
||||||
|
malloc_cprintf(write_cb, cbopaque, "[%zu]\n",
|
||||||
|
j - gap_start);
|
||||||
|
gap_start = -1;
|
||||||
|
}
|
||||||
|
malloc_cprintf(write_cb, cbopaque,
|
||||||
|
"%13zu %5zu %12"PRIu64" %12"PRIu64" %12"PRIu64
|
||||||
|
" %12zu %12zu\n",
|
||||||
|
run_size, run_size / pagesize, nmalloc, ndalloc,
|
||||||
|
nrequests, highruns, curruns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (gap_start != -1)
|
||||||
|
malloc_cprintf(write_cb, cbopaque, "[%zu]\n", j - gap_start);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque,
|
||||||
|
unsigned i)
|
||||||
|
{
|
||||||
|
unsigned nthreads;
|
||||||
|
size_t pagesize, pactive, pdirty, mapped;
|
||||||
|
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;
|
||||||
|
|
||||||
|
CTL_GET("arenas.pagesize", &pagesize, size_t);
|
||||||
|
|
||||||
|
CTL_I_GET("stats.arenas.0.nthreads", &nthreads, unsigned);
|
||||||
|
malloc_cprintf(write_cb, cbopaque,
|
||||||
|
"assigned threads: %u\n", nthreads);
|
||||||
|
CTL_I_GET("stats.arenas.0.pactive", &pactive, size_t);
|
||||||
|
CTL_I_GET("stats.arenas.0.pdirty", &pdirty, size_t);
|
||||||
|
CTL_I_GET("stats.arenas.0.npurge", &npurge, uint64_t);
|
||||||
|
CTL_I_GET("stats.arenas.0.nmadvise", &nmadvise, uint64_t);
|
||||||
|
CTL_I_GET("stats.arenas.0.purged", &purged, uint64_t);
|
||||||
|
malloc_cprintf(write_cb, cbopaque,
|
||||||
|
"dirty pages: %zu:%zu active:dirty, %"PRIu64" sweep%s,"
|
||||||
|
" %"PRIu64" madvise%s, %"PRIu64" purged\n",
|
||||||
|
pactive, pdirty, npurge, npurge == 1 ? "" : "s",
|
||||||
|
nmadvise, nmadvise == 1 ? "" : "s", purged);
|
||||||
|
|
||||||
|
malloc_cprintf(write_cb, cbopaque,
|
||||||
|
" allocated nmalloc ndalloc nrequests\n");
|
||||||
|
CTL_I_GET("stats.arenas.0.small.allocated", &small_allocated, size_t);
|
||||||
|
CTL_I_GET("stats.arenas.0.small.nmalloc", &small_nmalloc, uint64_t);
|
||||||
|
CTL_I_GET("stats.arenas.0.small.ndalloc", &small_ndalloc, uint64_t);
|
||||||
|
CTL_I_GET("stats.arenas.0.small.nrequests", &small_nrequests, uint64_t);
|
||||||
|
malloc_cprintf(write_cb, cbopaque,
|
||||||
|
"small: %12zu %12"PRIu64" %12"PRIu64" %12"PRIu64"\n",
|
||||||
|
small_allocated, small_nmalloc, small_ndalloc, small_nrequests);
|
||||||
|
CTL_I_GET("stats.arenas.0.large.allocated", &large_allocated, size_t);
|
||||||
|
CTL_I_GET("stats.arenas.0.large.nmalloc", &large_nmalloc, uint64_t);
|
||||||
|
CTL_I_GET("stats.arenas.0.large.ndalloc", &large_ndalloc, uint64_t);
|
||||||
|
CTL_I_GET("stats.arenas.0.large.nrequests", &large_nrequests, uint64_t);
|
||||||
|
malloc_cprintf(write_cb, cbopaque,
|
||||||
|
"large: %12zu %12"PRIu64" %12"PRIu64" %12"PRIu64"\n",
|
||||||
|
large_allocated, large_nmalloc, large_ndalloc, large_nrequests);
|
||||||
|
malloc_cprintf(write_cb, cbopaque,
|
||||||
|
"total: %12zu %12"PRIu64" %12"PRIu64" %12"PRIu64"\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 * pagesize );
|
||||||
|
CTL_I_GET("stats.arenas.0.mapped", &mapped, size_t);
|
||||||
|
malloc_cprintf(write_cb, cbopaque, "mapped: %12zu\n", mapped);
|
||||||
|
|
||||||
|
stats_arena_bins_print(write_cb, cbopaque, i);
|
||||||
|
stats_arena_lruns_print(write_cb, cbopaque, i);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
|
||||||
|
const char *opts)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
uint64_t epoch;
|
||||||
|
size_t u64sz;
|
||||||
|
char s[UMAX2S_BUFSIZE];
|
||||||
|
bool general = true;
|
||||||
|
bool merged = true;
|
||||||
|
bool unmerged = true;
|
||||||
|
bool bins = true;
|
||||||
|
bool large = true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 = JEMALLOC_P(mallctl)("epoch", &epoch, &u64sz, &epoch,
|
||||||
|
sizeof(uint64_t));
|
||||||
|
if (err != 0) {
|
||||||
|
if (err == EAGAIN) {
|
||||||
|
malloc_write("<jemalloc>: Memory allocation failure in "
|
||||||
|
"mallctl(\"epoch\", ...)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
malloc_write("<jemalloc>: Failure in mallctl(\"epoch\", "
|
||||||
|
"...)\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (write_cb == NULL) {
|
||||||
|
/*
|
||||||
|
* The caller did not provide an alternate write_cb callback
|
||||||
|
* function, so use the default one. malloc_write() is an
|
||||||
|
* inline function, so use malloc_message() directly here.
|
||||||
|
*/
|
||||||
|
write_cb = JEMALLOC_P(malloc_message);
|
||||||
|
cbopaque = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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:;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write_cb(cbopaque, "___ Begin jemalloc statistics ___\n");
|
||||||
|
if (general) {
|
||||||
|
int err;
|
||||||
|
const char *cpv;
|
||||||
|
bool bv;
|
||||||
|
unsigned uv;
|
||||||
|
ssize_t ssv;
|
||||||
|
size_t sv, bsz, ssz, sssz, cpsz;
|
||||||
|
|
||||||
|
bsz = sizeof(bool);
|
||||||
|
ssz = sizeof(size_t);
|
||||||
|
sssz = sizeof(ssize_t);
|
||||||
|
cpsz = sizeof(const char *);
|
||||||
|
|
||||||
|
CTL_GET("version", &cpv, const char *);
|
||||||
|
write_cb(cbopaque, "Version: ");
|
||||||
|
write_cb(cbopaque, cpv);
|
||||||
|
write_cb(cbopaque, "\n");
|
||||||
|
CTL_GET("config.debug", &bv, bool);
|
||||||
|
write_cb(cbopaque, "Assertions ");
|
||||||
|
write_cb(cbopaque, bv ? "enabled" : "disabled");
|
||||||
|
write_cb(cbopaque, "\n");
|
||||||
|
|
||||||
|
#define OPT_WRITE_BOOL(n) \
|
||||||
|
if ((err = JEMALLOC_P(mallctl)("opt."#n, &bv, &bsz, \
|
||||||
|
NULL, 0)) == 0) { \
|
||||||
|
write_cb(cbopaque, " opt."#n": "); \
|
||||||
|
write_cb(cbopaque, bv ? "true" : "false"); \
|
||||||
|
write_cb(cbopaque, "\n"); \
|
||||||
|
}
|
||||||
|
#define OPT_WRITE_SIZE_T(n) \
|
||||||
|
if ((err = JEMALLOC_P(mallctl)("opt."#n, &sv, &ssz, \
|
||||||
|
NULL, 0)) == 0) { \
|
||||||
|
write_cb(cbopaque, " opt."#n": "); \
|
||||||
|
write_cb(cbopaque, u2s(sv, 10, s)); \
|
||||||
|
write_cb(cbopaque, "\n"); \
|
||||||
|
}
|
||||||
|
#define OPT_WRITE_SSIZE_T(n) \
|
||||||
|
if ((err = JEMALLOC_P(mallctl)("opt."#n, &ssv, &sssz, \
|
||||||
|
NULL, 0)) == 0) { \
|
||||||
|
if (ssv >= 0) { \
|
||||||
|
write_cb(cbopaque, " opt."#n": "); \
|
||||||
|
write_cb(cbopaque, u2s(ssv, 10, s)); \
|
||||||
|
} else { \
|
||||||
|
write_cb(cbopaque, " opt."#n": -"); \
|
||||||
|
write_cb(cbopaque, u2s(-ssv, 10, s)); \
|
||||||
|
} \
|
||||||
|
write_cb(cbopaque, "\n"); \
|
||||||
|
}
|
||||||
|
#define OPT_WRITE_CHAR_P(n) \
|
||||||
|
if ((err = JEMALLOC_P(mallctl)("opt."#n, &cpv, &cpsz, \
|
||||||
|
NULL, 0)) == 0) { \
|
||||||
|
write_cb(cbopaque, " opt."#n": \""); \
|
||||||
|
write_cb(cbopaque, cpv); \
|
||||||
|
write_cb(cbopaque, "\"\n"); \
|
||||||
|
}
|
||||||
|
|
||||||
|
write_cb(cbopaque, "Run-time option settings:\n");
|
||||||
|
OPT_WRITE_BOOL(abort)
|
||||||
|
OPT_WRITE_SIZE_T(lg_qspace_max)
|
||||||
|
OPT_WRITE_SIZE_T(lg_cspace_max)
|
||||||
|
OPT_WRITE_SIZE_T(lg_chunk)
|
||||||
|
OPT_WRITE_SIZE_T(narenas)
|
||||||
|
OPT_WRITE_SSIZE_T(lg_dirty_mult)
|
||||||
|
OPT_WRITE_BOOL(stats_print)
|
||||||
|
OPT_WRITE_BOOL(junk)
|
||||||
|
OPT_WRITE_BOOL(zero)
|
||||||
|
OPT_WRITE_BOOL(sysv)
|
||||||
|
OPT_WRITE_BOOL(xmalloc)
|
||||||
|
OPT_WRITE_BOOL(tcache)
|
||||||
|
OPT_WRITE_SSIZE_T(lg_tcache_gc_sweep)
|
||||||
|
OPT_WRITE_SSIZE_T(lg_tcache_max)
|
||||||
|
OPT_WRITE_BOOL(prof)
|
||||||
|
OPT_WRITE_CHAR_P(prof_prefix)
|
||||||
|
OPT_WRITE_SIZE_T(lg_prof_bt_max)
|
||||||
|
OPT_WRITE_BOOL(prof_active)
|
||||||
|
OPT_WRITE_SSIZE_T(lg_prof_sample)
|
||||||
|
OPT_WRITE_BOOL(prof_accum)
|
||||||
|
OPT_WRITE_SSIZE_T(lg_prof_tcmax)
|
||||||
|
OPT_WRITE_SSIZE_T(lg_prof_interval)
|
||||||
|
OPT_WRITE_BOOL(prof_gdump)
|
||||||
|
OPT_WRITE_BOOL(prof_leak)
|
||||||
|
OPT_WRITE_BOOL(overcommit)
|
||||||
|
|
||||||
|
#undef OPT_WRITE_BOOL
|
||||||
|
#undef OPT_WRITE_SIZE_T
|
||||||
|
#undef OPT_WRITE_SSIZE_T
|
||||||
|
#undef OPT_WRITE_CHAR_P
|
||||||
|
|
||||||
|
write_cb(cbopaque, "CPUs: ");
|
||||||
|
write_cb(cbopaque, u2s(ncpus, 10, s));
|
||||||
|
write_cb(cbopaque, "\n");
|
||||||
|
|
||||||
|
CTL_GET("arenas.narenas", &uv, unsigned);
|
||||||
|
write_cb(cbopaque, "Max arenas: ");
|
||||||
|
write_cb(cbopaque, u2s(uv, 10, s));
|
||||||
|
write_cb(cbopaque, "\n");
|
||||||
|
|
||||||
|
write_cb(cbopaque, "Pointer size: ");
|
||||||
|
write_cb(cbopaque, u2s(sizeof(void *), 10, s));
|
||||||
|
write_cb(cbopaque, "\n");
|
||||||
|
|
||||||
|
CTL_GET("arenas.quantum", &sv, size_t);
|
||||||
|
write_cb(cbopaque, "Quantum size: ");
|
||||||
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
|
write_cb(cbopaque, "\n");
|
||||||
|
|
||||||
|
CTL_GET("arenas.cacheline", &sv, size_t);
|
||||||
|
write_cb(cbopaque, "Cacheline size (assumed): ");
|
||||||
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
|
write_cb(cbopaque, "\n");
|
||||||
|
|
||||||
|
CTL_GET("arenas.subpage", &sv, size_t);
|
||||||
|
write_cb(cbopaque, "Subpage spacing: ");
|
||||||
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
|
write_cb(cbopaque, "\n");
|
||||||
|
|
||||||
|
if ((err = JEMALLOC_P(mallctl)("arenas.tspace_min", &sv, &ssz,
|
||||||
|
NULL, 0)) == 0) {
|
||||||
|
write_cb(cbopaque, "Tiny 2^n-spaced sizes: [");
|
||||||
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
|
write_cb(cbopaque, "..");
|
||||||
|
|
||||||
|
CTL_GET("arenas.tspace_max", &sv, size_t);
|
||||||
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
|
write_cb(cbopaque, "]\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
CTL_GET("arenas.qspace_min", &sv, size_t);
|
||||||
|
write_cb(cbopaque, "Quantum-spaced sizes: [");
|
||||||
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
|
write_cb(cbopaque, "..");
|
||||||
|
CTL_GET("arenas.qspace_max", &sv, size_t);
|
||||||
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
|
write_cb(cbopaque, "]\n");
|
||||||
|
|
||||||
|
CTL_GET("arenas.cspace_min", &sv, size_t);
|
||||||
|
write_cb(cbopaque, "Cacheline-spaced sizes: [");
|
||||||
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
|
write_cb(cbopaque, "..");
|
||||||
|
CTL_GET("arenas.cspace_max", &sv, size_t);
|
||||||
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
|
write_cb(cbopaque, "]\n");
|
||||||
|
|
||||||
|
CTL_GET("arenas.sspace_min", &sv, size_t);
|
||||||
|
write_cb(cbopaque, "Subpage-spaced sizes: [");
|
||||||
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
|
write_cb(cbopaque, "..");
|
||||||
|
CTL_GET("arenas.sspace_max", &sv, size_t);
|
||||||
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
|
write_cb(cbopaque, "]\n");
|
||||||
|
|
||||||
|
CTL_GET("opt.lg_dirty_mult", &ssv, ssize_t);
|
||||||
|
if (ssv >= 0) {
|
||||||
|
write_cb(cbopaque,
|
||||||
|
"Min active:dirty page ratio per arena: ");
|
||||||
|
write_cb(cbopaque, u2s((1U << ssv), 10, s));
|
||||||
|
write_cb(cbopaque, ":1\n");
|
||||||
|
} else {
|
||||||
|
write_cb(cbopaque,
|
||||||
|
"Min active:dirty page ratio per arena: N/A\n");
|
||||||
|
}
|
||||||
|
if ((err = JEMALLOC_P(mallctl)("arenas.tcache_max", &sv,
|
||||||
|
&ssz, NULL, 0)) == 0) {
|
||||||
|
write_cb(cbopaque,
|
||||||
|
"Maximum thread-cached size class: ");
|
||||||
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
|
write_cb(cbopaque, "\n");
|
||||||
|
}
|
||||||
|
if ((err = JEMALLOC_P(mallctl)("opt.lg_tcache_gc_sweep", &ssv,
|
||||||
|
&ssz, NULL, 0)) == 0) {
|
||||||
|
size_t tcache_gc_sweep = (1U << ssv);
|
||||||
|
bool tcache_enabled;
|
||||||
|
CTL_GET("opt.tcache", &tcache_enabled, bool);
|
||||||
|
write_cb(cbopaque, "Thread cache GC sweep interval: ");
|
||||||
|
write_cb(cbopaque, tcache_enabled && ssv >= 0 ?
|
||||||
|
u2s(tcache_gc_sweep, 10, s) : "N/A");
|
||||||
|
write_cb(cbopaque, "\n");
|
||||||
|
}
|
||||||
|
if ((err = JEMALLOC_P(mallctl)("opt.prof", &bv, &bsz, NULL, 0))
|
||||||
|
== 0 && bv) {
|
||||||
|
CTL_GET("opt.lg_prof_bt_max", &sv, size_t);
|
||||||
|
write_cb(cbopaque, "Maximum profile backtrace depth: ");
|
||||||
|
write_cb(cbopaque, u2s((1U << sv), 10, s));
|
||||||
|
write_cb(cbopaque, "\n");
|
||||||
|
|
||||||
|
CTL_GET("opt.lg_prof_tcmax", &ssv, ssize_t);
|
||||||
|
write_cb(cbopaque,
|
||||||
|
"Maximum per thread backtrace cache: ");
|
||||||
|
if (ssv >= 0) {
|
||||||
|
write_cb(cbopaque, u2s((1U << ssv), 10, s));
|
||||||
|
write_cb(cbopaque, " (2^");
|
||||||
|
write_cb(cbopaque, u2s(ssv, 10, s));
|
||||||
|
write_cb(cbopaque, ")\n");
|
||||||
|
} else
|
||||||
|
write_cb(cbopaque, "N/A\n");
|
||||||
|
|
||||||
|
CTL_GET("opt.lg_prof_sample", &sv, size_t);
|
||||||
|
write_cb(cbopaque, "Average profile sample interval: ");
|
||||||
|
write_cb(cbopaque, u2s((((uint64_t)1U) << sv), 10, s));
|
||||||
|
write_cb(cbopaque, " (2^");
|
||||||
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
|
write_cb(cbopaque, ")\n");
|
||||||
|
|
||||||
|
CTL_GET("opt.lg_prof_interval", &ssv, ssize_t);
|
||||||
|
write_cb(cbopaque, "Average profile dump interval: ");
|
||||||
|
if (ssv >= 0) {
|
||||||
|
write_cb(cbopaque, u2s((((uint64_t)1U) << ssv),
|
||||||
|
10, s));
|
||||||
|
write_cb(cbopaque, " (2^");
|
||||||
|
write_cb(cbopaque, u2s(ssv, 10, s));
|
||||||
|
write_cb(cbopaque, ")\n");
|
||||||
|
} else
|
||||||
|
write_cb(cbopaque, "N/A\n");
|
||||||
|
}
|
||||||
|
CTL_GET("arenas.chunksize", &sv, size_t);
|
||||||
|
write_cb(cbopaque, "Chunk size: ");
|
||||||
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
|
CTL_GET("opt.lg_chunk", &sv, size_t);
|
||||||
|
write_cb(cbopaque, " (2^");
|
||||||
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
|
write_cb(cbopaque, ")\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
size_t sszp, ssz;
|
||||||
|
size_t *cactive;
|
||||||
|
size_t allocated, active, mapped;
|
||||||
|
size_t chunks_current, chunks_high, swap_avail;
|
||||||
|
uint64_t chunks_total;
|
||||||
|
size_t huge_allocated;
|
||||||
|
uint64_t huge_nmalloc, huge_ndalloc;
|
||||||
|
|
||||||
|
sszp = sizeof(size_t *);
|
||||||
|
ssz = sizeof(size_t);
|
||||||
|
|
||||||
|
CTL_GET("stats.cactive", &cactive, size_t *);
|
||||||
|
CTL_GET("stats.allocated", &allocated, size_t);
|
||||||
|
CTL_GET("stats.active", &active, size_t);
|
||||||
|
CTL_GET("stats.mapped", &mapped, size_t);
|
||||||
|
malloc_cprintf(write_cb, cbopaque,
|
||||||
|
"Allocated: %zu, active: %zu, mapped: %zu\n",
|
||||||
|
allocated, active, mapped);
|
||||||
|
malloc_cprintf(write_cb, cbopaque,
|
||||||
|
"Current active ceiling: %zu\n", atomic_read_z(cactive));
|
||||||
|
|
||||||
|
/* Print chunk stats. */
|
||||||
|
CTL_GET("stats.chunks.total", &chunks_total, uint64_t);
|
||||||
|
CTL_GET("stats.chunks.high", &chunks_high, size_t);
|
||||||
|
CTL_GET("stats.chunks.current", &chunks_current, size_t);
|
||||||
|
if ((err = JEMALLOC_P(mallctl)("swap.avail", &swap_avail, &ssz,
|
||||||
|
NULL, 0)) == 0) {
|
||||||
|
size_t lg_chunk;
|
||||||
|
|
||||||
|
malloc_cprintf(write_cb, cbopaque, "chunks: nchunks "
|
||||||
|
"highchunks curchunks swap_avail\n");
|
||||||
|
CTL_GET("opt.lg_chunk", &lg_chunk, size_t);
|
||||||
|
malloc_cprintf(write_cb, cbopaque,
|
||||||
|
" %13"PRIu64"%13zu%13zu%13zu\n",
|
||||||
|
chunks_total, chunks_high, chunks_current,
|
||||||
|
swap_avail << lg_chunk);
|
||||||
|
} else {
|
||||||
|
malloc_cprintf(write_cb, cbopaque, "chunks: nchunks "
|
||||||
|
"highchunks curchunks\n");
|
||||||
|
malloc_cprintf(write_cb, cbopaque,
|
||||||
|
" %13"PRIu64"%13zu%13zu\n",
|
||||||
|
chunks_total, chunks_high, chunks_current);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print huge stats. */
|
||||||
|
CTL_GET("stats.huge.nmalloc", &huge_nmalloc, uint64_t);
|
||||||
|
CTL_GET("stats.huge.ndalloc", &huge_ndalloc, uint64_t);
|
||||||
|
CTL_GET("stats.huge.allocated", &huge_allocated, size_t);
|
||||||
|
malloc_cprintf(write_cb, cbopaque,
|
||||||
|
"huge: nmalloc ndalloc allocated\n");
|
||||||
|
malloc_cprintf(write_cb, cbopaque,
|
||||||
|
" %12"PRIu64" %12"PRIu64" %12zu\n",
|
||||||
|
huge_nmalloc, huge_ndalloc, huge_allocated);
|
||||||
|
|
||||||
|
if (merged) {
|
||||||
|
unsigned narenas;
|
||||||
|
|
||||||
|
CTL_GET("arenas.narenas", &narenas, unsigned);
|
||||||
|
{
|
||||||
|
bool initialized[narenas];
|
||||||
|
size_t isz;
|
||||||
|
unsigned i, ninitialized;
|
||||||
|
|
||||||
|
isz = sizeof(initialized);
|
||||||
|
xmallctl("arenas.initialized", initialized,
|
||||||
|
&isz, NULL, 0);
|
||||||
|
for (i = ninitialized = 0; i < narenas; i++) {
|
||||||
|
if (initialized[i])
|
||||||
|
ninitialized++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ninitialized > 1) {
|
||||||
|
/* Print merged arena stats. */
|
||||||
|
malloc_cprintf(write_cb, cbopaque,
|
||||||
|
"\nMerged arenas stats:\n");
|
||||||
|
stats_arena_print(write_cb, cbopaque,
|
||||||
|
narenas);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unmerged) {
|
||||||
|
unsigned narenas;
|
||||||
|
|
||||||
|
/* Print stats for each arena. */
|
||||||
|
|
||||||
|
CTL_GET("arenas.narenas", &narenas, unsigned);
|
||||||
|
{
|
||||||
|
bool initialized[narenas];
|
||||||
|
size_t isz;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
isz = sizeof(initialized);
|
||||||
|
xmallctl("arenas.initialized", initialized,
|
||||||
|
&isz, NULL, 0);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* #ifdef JEMALLOC_STATS */
|
||||||
|
write_cb(cbopaque, "--- End jemalloc statistics ---\n");
|
||||||
|
}
|
||||||
480
src/tcache.c
Normal file
480
src/tcache.c
Normal file
@@ -0,0 +1,480 @@
|
|||||||
|
#define JEMALLOC_TCACHE_C_
|
||||||
|
#include "jemalloc/internal/jemalloc_internal.h"
|
||||||
|
#ifdef JEMALLOC_TCACHE
|
||||||
|
/******************************************************************************/
|
||||||
|
/* Data. */
|
||||||
|
|
||||||
|
bool opt_tcache = true;
|
||||||
|
ssize_t opt_lg_tcache_max = LG_TCACHE_MAXCLASS_DEFAULT;
|
||||||
|
ssize_t opt_lg_tcache_gc_sweep = LG_TCACHE_GC_SWEEP_DEFAULT;
|
||||||
|
|
||||||
|
tcache_bin_info_t *tcache_bin_info;
|
||||||
|
static unsigned stack_nelms; /* Total stack elms per tcache. */
|
||||||
|
|
||||||
|
/* Map of thread-specific caches. */
|
||||||
|
#ifndef NO_TLS
|
||||||
|
__thread tcache_t *tcache_tls JEMALLOC_ATTR(tls_model("initial-exec"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Same contents as tcache, but initialized such that the TSD destructor is
|
||||||
|
* called when a thread exits, so that the cache can be cleaned up.
|
||||||
|
*/
|
||||||
|
pthread_key_t tcache_tsd;
|
||||||
|
|
||||||
|
size_t nhbins;
|
||||||
|
size_t tcache_maxclass;
|
||||||
|
unsigned tcache_gc_incr;
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/* Function prototypes for non-inline static functions. */
|
||||||
|
|
||||||
|
static void tcache_thread_cleanup(void *arg);
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
void *
|
||||||
|
tcache_alloc_small_hard(tcache_t *tcache, tcache_bin_t *tbin, size_t binind)
|
||||||
|
{
|
||||||
|
void *ret;
|
||||||
|
|
||||||
|
arena_tcache_fill_small(tcache->arena, tbin, binind
|
||||||
|
#ifdef JEMALLOC_PROF
|
||||||
|
, tcache->prof_accumbytes
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
#ifdef JEMALLOC_PROF
|
||||||
|
tcache->prof_accumbytes = 0;
|
||||||
|
#endif
|
||||||
|
ret = tcache_alloc_easy(tbin);
|
||||||
|
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tcache_bin_flush_small(tcache_bin_t *tbin, size_t binind, unsigned rem
|
||||||
|
#if (defined(JEMALLOC_STATS) || defined(JEMALLOC_PROF))
|
||||||
|
, tcache_t *tcache
|
||||||
|
#endif
|
||||||
|
)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
unsigned i, nflush, ndeferred;
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
bool merged_stats = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assert(binind < nbins);
|
||||||
|
assert(rem <= tbin->ncached);
|
||||||
|
|
||||||
|
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[0]);
|
||||||
|
arena_t *arena = chunk->arena;
|
||||||
|
arena_bin_t *bin = &arena->bins[binind];
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_PROF
|
||||||
|
if (arena == tcache->arena) {
|
||||||
|
malloc_mutex_lock(&arena->lock);
|
||||||
|
arena_prof_accum(arena, tcache->prof_accumbytes);
|
||||||
|
malloc_mutex_unlock(&arena->lock);
|
||||||
|
tcache->prof_accumbytes = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
malloc_mutex_lock(&bin->lock);
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
if (arena == tcache->arena) {
|
||||||
|
assert(merged_stats == false);
|
||||||
|
merged_stats = true;
|
||||||
|
bin->stats.nflushes++;
|
||||||
|
bin->stats.nrequests += tbin->tstats.nrequests;
|
||||||
|
tbin->tstats.nrequests = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
ndeferred = 0;
|
||||||
|
for (i = 0; i < nflush; i++) {
|
||||||
|
ptr = tbin->avail[i];
|
||||||
|
assert(ptr != NULL);
|
||||||
|
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
||||||
|
if (chunk->arena == arena) {
|
||||||
|
size_t pageind = ((uintptr_t)ptr -
|
||||||
|
(uintptr_t)chunk) >> PAGE_SHIFT;
|
||||||
|
arena_chunk_map_t *mapelm =
|
||||||
|
&chunk->map[pageind-map_bias];
|
||||||
|
arena_dalloc_bin(arena, chunk, ptr, mapelm);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* This object was allocated via a different
|
||||||
|
* arena bin than the one that is currently
|
||||||
|
* locked. Stash the object, so that it can be
|
||||||
|
* handled in a future pass.
|
||||||
|
*/
|
||||||
|
tbin->avail[ndeferred] = ptr;
|
||||||
|
ndeferred++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
malloc_mutex_unlock(&bin->lock);
|
||||||
|
}
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
if (merged_stats == false) {
|
||||||
|
/*
|
||||||
|
* The flush loop didn't happen to flush to this thread's
|
||||||
|
* arena, so the stats didn't get merged. Manually do so now.
|
||||||
|
*/
|
||||||
|
arena_bin_t *bin = &tcache->arena->bins[binind];
|
||||||
|
malloc_mutex_lock(&bin->lock);
|
||||||
|
bin->stats.nflushes++;
|
||||||
|
bin->stats.nrequests += tbin->tstats.nrequests;
|
||||||
|
tbin->tstats.nrequests = 0;
|
||||||
|
malloc_mutex_unlock(&bin->lock);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
memmove(tbin->avail, &tbin->avail[tbin->ncached - rem],
|
||||||
|
rem * sizeof(void *));
|
||||||
|
tbin->ncached = rem;
|
||||||
|
if ((int)tbin->ncached < tbin->low_water)
|
||||||
|
tbin->low_water = tbin->ncached;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tcache_bin_flush_large(tcache_bin_t *tbin, size_t binind, unsigned rem
|
||||||
|
#if (defined(JEMALLOC_STATS) || defined(JEMALLOC_PROF))
|
||||||
|
, tcache_t *tcache
|
||||||
|
#endif
|
||||||
|
)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
unsigned i, nflush, ndeferred;
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
bool merged_stats = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assert(binind < nhbins);
|
||||||
|
assert(rem <= tbin->ncached);
|
||||||
|
|
||||||
|
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[0]);
|
||||||
|
arena_t *arena = chunk->arena;
|
||||||
|
|
||||||
|
malloc_mutex_lock(&arena->lock);
|
||||||
|
#if (defined(JEMALLOC_PROF) || defined(JEMALLOC_STATS))
|
||||||
|
if (arena == tcache->arena) {
|
||||||
|
#endif
|
||||||
|
#ifdef JEMALLOC_PROF
|
||||||
|
arena_prof_accum(arena, tcache->prof_accumbytes);
|
||||||
|
tcache->prof_accumbytes = 0;
|
||||||
|
#endif
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
merged_stats = true;
|
||||||
|
arena->stats.nrequests_large += tbin->tstats.nrequests;
|
||||||
|
arena->stats.lstats[binind - nbins].nrequests +=
|
||||||
|
tbin->tstats.nrequests;
|
||||||
|
tbin->tstats.nrequests = 0;
|
||||||
|
#endif
|
||||||
|
#if (defined(JEMALLOC_PROF) || defined(JEMALLOC_STATS))
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
ndeferred = 0;
|
||||||
|
for (i = 0; i < nflush; i++) {
|
||||||
|
ptr = tbin->avail[i];
|
||||||
|
assert(ptr != NULL);
|
||||||
|
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
||||||
|
if (chunk->arena == arena)
|
||||||
|
arena_dalloc_large(arena, chunk, ptr);
|
||||||
|
else {
|
||||||
|
/*
|
||||||
|
* This object was allocated via a different
|
||||||
|
* arena than the one that is currently locked.
|
||||||
|
* Stash the object, so that it can be handled
|
||||||
|
* in a future pass.
|
||||||
|
*/
|
||||||
|
tbin->avail[ndeferred] = ptr;
|
||||||
|
ndeferred++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
malloc_mutex_unlock(&arena->lock);
|
||||||
|
}
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
if (merged_stats == false) {
|
||||||
|
/*
|
||||||
|
* The flush loop didn't happen to flush to this thread's
|
||||||
|
* arena, so the stats didn't get merged. Manually do so now.
|
||||||
|
*/
|
||||||
|
arena_t *arena = tcache->arena;
|
||||||
|
malloc_mutex_lock(&arena->lock);
|
||||||
|
arena->stats.nrequests_large += tbin->tstats.nrequests;
|
||||||
|
arena->stats.lstats[binind - nbins].nrequests +=
|
||||||
|
tbin->tstats.nrequests;
|
||||||
|
tbin->tstats.nrequests = 0;
|
||||||
|
malloc_mutex_unlock(&arena->lock);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
memmove(tbin->avail, &tbin->avail[tbin->ncached - rem],
|
||||||
|
rem * sizeof(void *));
|
||||||
|
tbin->ncached = rem;
|
||||||
|
if ((int)tbin->ncached < tbin->low_water)
|
||||||
|
tbin->low_water = tbin->ncached;
|
||||||
|
}
|
||||||
|
|
||||||
|
tcache_t *
|
||||||
|
tcache_create(arena_t *arena)
|
||||||
|
{
|
||||||
|
tcache_t *tcache;
|
||||||
|
size_t size, stack_offset;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
size = offsetof(tcache_t, tbins) + (sizeof(tcache_bin_t) * nhbins);
|
||||||
|
/* Naturally align the pointer stacks. */
|
||||||
|
size = PTR_CEILING(size);
|
||||||
|
stack_offset = size;
|
||||||
|
size += stack_nelms * sizeof(void *);
|
||||||
|
/*
|
||||||
|
* Round up to the nearest multiple of the cacheline size, in order to
|
||||||
|
* avoid the possibility of false cacheline sharing.
|
||||||
|
*
|
||||||
|
* That this works relies on the same logic as in ipalloc(), but we
|
||||||
|
* cannot directly call ipalloc() here due to tcache bootstrapping
|
||||||
|
* issues.
|
||||||
|
*/
|
||||||
|
size = (size + CACHELINE_MASK) & (-CACHELINE);
|
||||||
|
|
||||||
|
if (size <= small_maxclass)
|
||||||
|
tcache = (tcache_t *)arena_malloc_small(arena, size, true);
|
||||||
|
else if (size <= tcache_maxclass)
|
||||||
|
tcache = (tcache_t *)arena_malloc_large(arena, size, true);
|
||||||
|
else
|
||||||
|
tcache = (tcache_t *)icalloc(size);
|
||||||
|
|
||||||
|
if (tcache == NULL)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
/* Link into list of extant tcaches. */
|
||||||
|
malloc_mutex_lock(&arena->lock);
|
||||||
|
ql_elm_new(tcache, link);
|
||||||
|
ql_tail_insert(&arena->tcache_ql, tcache, link);
|
||||||
|
malloc_mutex_unlock(&arena->lock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
tcache->arena = arena;
|
||||||
|
assert((TCACHE_NSLOTS_SMALL_MAX & 1U) == 0);
|
||||||
|
for (i = 0; i < nhbins; i++) {
|
||||||
|
tcache->tbins[i].lg_fill_div = 1;
|
||||||
|
tcache->tbins[i].avail = (void **)((uintptr_t)tcache +
|
||||||
|
(uintptr_t)stack_offset);
|
||||||
|
stack_offset += tcache_bin_info[i].ncached_max * sizeof(void *);
|
||||||
|
}
|
||||||
|
|
||||||
|
TCACHE_SET(tcache);
|
||||||
|
|
||||||
|
return (tcache);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tcache_destroy(tcache_t *tcache)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
size_t tcache_size;
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
/* Unlink from list of extant tcaches. */
|
||||||
|
malloc_mutex_lock(&tcache->arena->lock);
|
||||||
|
ql_remove(&tcache->arena->tcache_ql, tcache, link);
|
||||||
|
malloc_mutex_unlock(&tcache->arena->lock);
|
||||||
|
tcache_stats_merge(tcache, tcache->arena);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (i = 0; i < nbins; i++) {
|
||||||
|
tcache_bin_t *tbin = &tcache->tbins[i];
|
||||||
|
tcache_bin_flush_small(tbin, i, 0
|
||||||
|
#if (defined(JEMALLOC_STATS) || defined(JEMALLOC_PROF))
|
||||||
|
, tcache
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
if (tbin->tstats.nrequests != 0) {
|
||||||
|
arena_t *arena = tcache->arena;
|
||||||
|
arena_bin_t *bin = &arena->bins[i];
|
||||||
|
malloc_mutex_lock(&bin->lock);
|
||||||
|
bin->stats.nrequests += tbin->tstats.nrequests;
|
||||||
|
malloc_mutex_unlock(&bin->lock);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i < nhbins; i++) {
|
||||||
|
tcache_bin_t *tbin = &tcache->tbins[i];
|
||||||
|
tcache_bin_flush_large(tbin, i, 0
|
||||||
|
#if (defined(JEMALLOC_STATS) || defined(JEMALLOC_PROF))
|
||||||
|
, tcache
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
if (tbin->tstats.nrequests != 0) {
|
||||||
|
arena_t *arena = tcache->arena;
|
||||||
|
malloc_mutex_lock(&arena->lock);
|
||||||
|
arena->stats.nrequests_large += tbin->tstats.nrequests;
|
||||||
|
arena->stats.lstats[i - nbins].nrequests +=
|
||||||
|
tbin->tstats.nrequests;
|
||||||
|
malloc_mutex_unlock(&arena->lock);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_PROF
|
||||||
|
if (tcache->prof_accumbytes > 0) {
|
||||||
|
malloc_mutex_lock(&tcache->arena->lock);
|
||||||
|
arena_prof_accum(tcache->arena, tcache->prof_accumbytes);
|
||||||
|
malloc_mutex_unlock(&tcache->arena->lock);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
tcache_size = arena_salloc(tcache);
|
||||||
|
if (tcache_size <= small_maxclass) {
|
||||||
|
arena_chunk_t *chunk = CHUNK_ADDR2BASE(tcache);
|
||||||
|
arena_t *arena = chunk->arena;
|
||||||
|
size_t pageind = ((uintptr_t)tcache - (uintptr_t)chunk) >>
|
||||||
|
PAGE_SHIFT;
|
||||||
|
arena_chunk_map_t *mapelm = &chunk->map[pageind-map_bias];
|
||||||
|
arena_run_t *run = (arena_run_t *)((uintptr_t)chunk +
|
||||||
|
(uintptr_t)((pageind - (mapelm->bits >> PAGE_SHIFT)) <<
|
||||||
|
PAGE_SHIFT));
|
||||||
|
arena_bin_t *bin = run->bin;
|
||||||
|
|
||||||
|
malloc_mutex_lock(&bin->lock);
|
||||||
|
arena_dalloc_bin(arena, chunk, tcache, mapelm);
|
||||||
|
malloc_mutex_unlock(&bin->lock);
|
||||||
|
} else if (tcache_size <= tcache_maxclass) {
|
||||||
|
arena_chunk_t *chunk = CHUNK_ADDR2BASE(tcache);
|
||||||
|
arena_t *arena = chunk->arena;
|
||||||
|
|
||||||
|
malloc_mutex_lock(&arena->lock);
|
||||||
|
arena_dalloc_large(arena, chunk, tcache);
|
||||||
|
malloc_mutex_unlock(&arena->lock);
|
||||||
|
} else
|
||||||
|
idalloc(tcache);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
tcache_thread_cleanup(void *arg)
|
||||||
|
{
|
||||||
|
tcache_t *tcache = (tcache_t *)arg;
|
||||||
|
|
||||||
|
if (tcache == (void *)(uintptr_t)1) {
|
||||||
|
/*
|
||||||
|
* The previous time this destructor was called, we set the key
|
||||||
|
* to 1 so that other destructors wouldn't cause re-creation of
|
||||||
|
* the tcache. This time, do nothing, so that the destructor
|
||||||
|
* will not be called again.
|
||||||
|
*/
|
||||||
|
} else if (tcache == (void *)(uintptr_t)2) {
|
||||||
|
/*
|
||||||
|
* Another destructor called an allocator function after this
|
||||||
|
* destructor was called. Reset tcache to 1 in order to
|
||||||
|
* receive another callback.
|
||||||
|
*/
|
||||||
|
TCACHE_SET((uintptr_t)1);
|
||||||
|
} else if (tcache != NULL) {
|
||||||
|
assert(tcache != (void *)(uintptr_t)1);
|
||||||
|
tcache_destroy(tcache);
|
||||||
|
TCACHE_SET((uintptr_t)1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
void
|
||||||
|
tcache_stats_merge(tcache_t *tcache, arena_t *arena)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
/* 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];
|
||||||
|
malloc_mutex_lock(&bin->lock);
|
||||||
|
bin->stats.nrequests += tbin->tstats.nrequests;
|
||||||
|
malloc_mutex_unlock(&bin->lock);
|
||||||
|
tbin->tstats.nrequests = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
tbin->tstats.nrequests = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool
|
||||||
|
tcache_boot(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (opt_tcache) {
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If necessary, clamp opt_lg_tcache_max, now that
|
||||||
|
* small_maxclass and arena_maxclass are known.
|
||||||
|
*/
|
||||||
|
if (opt_lg_tcache_max < 0 || (1U <<
|
||||||
|
opt_lg_tcache_max) < small_maxclass)
|
||||||
|
tcache_maxclass = small_maxclass;
|
||||||
|
else if ((1U << opt_lg_tcache_max) > arena_maxclass)
|
||||||
|
tcache_maxclass = arena_maxclass;
|
||||||
|
else
|
||||||
|
tcache_maxclass = (1U << opt_lg_tcache_max);
|
||||||
|
|
||||||
|
nhbins = nbins + (tcache_maxclass >> PAGE_SHIFT);
|
||||||
|
|
||||||
|
/* Initialize tcache_bin_info. */
|
||||||
|
tcache_bin_info = (tcache_bin_info_t *)base_alloc(nhbins *
|
||||||
|
sizeof(tcache_bin_info_t));
|
||||||
|
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_MAX) {
|
||||||
|
tcache_bin_info[i].ncached_max =
|
||||||
|
(arena_bin_info[i].nregs << 1);
|
||||||
|
} else {
|
||||||
|
tcache_bin_info[i].ncached_max =
|
||||||
|
TCACHE_NSLOTS_SMALL_MAX;
|
||||||
|
}
|
||||||
|
stack_nelms += tcache_bin_info[i].ncached_max;
|
||||||
|
}
|
||||||
|
for (; i < nhbins; i++) {
|
||||||
|
tcache_bin_info[i].ncached_max = TCACHE_NSLOTS_LARGE;
|
||||||
|
stack_nelms += tcache_bin_info[i].ncached_max;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute incremental GC event threshold. */
|
||||||
|
if (opt_lg_tcache_gc_sweep >= 0) {
|
||||||
|
tcache_gc_incr = ((1U << opt_lg_tcache_gc_sweep) /
|
||||||
|
nbins) + (((1U << opt_lg_tcache_gc_sweep) % nbins ==
|
||||||
|
0) ? 0 : 1);
|
||||||
|
} else
|
||||||
|
tcache_gc_incr = 0;
|
||||||
|
|
||||||
|
if (pthread_key_create(&tcache_tsd, tcache_thread_cleanup) !=
|
||||||
|
0) {
|
||||||
|
malloc_write(
|
||||||
|
"<jemalloc>: Error in pthread_key_create()\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
/******************************************************************************/
|
||||||
|
#endif /* JEMALLOC_TCACHE */
|
||||||
354
src/zone.c
Normal file
354
src/zone.c
Normal file
@@ -0,0 +1,354 @@
|
|||||||
|
#include "jemalloc/internal/jemalloc_internal.h"
|
||||||
|
#ifndef JEMALLOC_ZONE
|
||||||
|
# error "This source file is for zones on Darwin (OS X)."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/* Data. */
|
||||||
|
|
||||||
|
static malloc_zone_t zone, szone;
|
||||||
|
static struct malloc_introspection_t zone_introspect, ozone_introspect;
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/* Function prototypes for non-inline static functions. */
|
||||||
|
|
||||||
|
static size_t zone_size(malloc_zone_t *zone, 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 >= 6)
|
||||||
|
static void *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);
|
||||||
|
#endif
|
||||||
|
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);
|
||||||
|
static size_t ozone_size(malloc_zone_t *zone, void *ptr);
|
||||||
|
static void ozone_free(malloc_zone_t *zone, void *ptr);
|
||||||
|
static void *ozone_realloc(malloc_zone_t *zone, void *ptr, size_t size);
|
||||||
|
static unsigned ozone_batch_malloc(malloc_zone_t *zone, size_t size,
|
||||||
|
void **results, unsigned num_requested);
|
||||||
|
static void ozone_batch_free(malloc_zone_t *zone, void **to_be_freed,
|
||||||
|
unsigned num);
|
||||||
|
#if (JEMALLOC_ZONE_VERSION >= 6)
|
||||||
|
static void ozone_free_definite_size(malloc_zone_t *zone, void *ptr,
|
||||||
|
size_t size);
|
||||||
|
#endif
|
||||||
|
static void ozone_force_lock(malloc_zone_t *zone);
|
||||||
|
static void ozone_force_unlock(malloc_zone_t *zone);
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*
|
||||||
|
* Functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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
|
||||||
|
* we knew that all pointers were owned by *some* zone, we could split
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
return (ivsalloc(ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
zone_malloc(malloc_zone_t *zone, size_t size)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (JEMALLOC_P(malloc)(size));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
zone_calloc(malloc_zone_t *zone, size_t num, size_t size)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (JEMALLOC_P(calloc)(num, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
zone_valloc(malloc_zone_t *zone, size_t size)
|
||||||
|
{
|
||||||
|
void *ret = NULL; /* Assignment avoids useless compiler warning. */
|
||||||
|
|
||||||
|
JEMALLOC_P(posix_memalign)(&ret, PAGE_SIZE, size);
|
||||||
|
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
zone_free(malloc_zone_t *zone, void *ptr)
|
||||||
|
{
|
||||||
|
|
||||||
|
JEMALLOC_P(free)(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
zone_realloc(malloc_zone_t *zone, void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (JEMALLOC_P(realloc)(ptr, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (JEMALLOC_ZONE_VERSION >= 6)
|
||||||
|
static void *
|
||||||
|
zone_memalign(malloc_zone_t *zone, size_t alignment, size_t size)
|
||||||
|
{
|
||||||
|
void *ret = NULL; /* Assignment avoids useless compiler warning. */
|
||||||
|
|
||||||
|
JEMALLOC_P(posix_memalign)(&ret, alignment, size);
|
||||||
|
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
zone_free_definite_size(malloc_zone_t *zone, void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
|
||||||
|
assert(ivsalloc(ptr) == size);
|
||||||
|
JEMALLOC_P(free)(ptr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void *
|
||||||
|
zone_destroy(malloc_zone_t *zone)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* This function should never be called. */
|
||||||
|
assert(false);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
zone_good_size(malloc_zone_t *zone, size_t size)
|
||||||
|
{
|
||||||
|
size_t ret;
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Actually create an object of the appropriate size, then find out
|
||||||
|
* how large it could have been without moving up to the next size
|
||||||
|
* class.
|
||||||
|
*/
|
||||||
|
p = JEMALLOC_P(malloc)(size);
|
||||||
|
if (p != NULL) {
|
||||||
|
ret = isalloc(p);
|
||||||
|
JEMALLOC_P(free)(p);
|
||||||
|
} else
|
||||||
|
ret = size;
|
||||||
|
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
zone_force_lock(malloc_zone_t *zone)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (isthreaded)
|
||||||
|
jemalloc_prefork();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
zone_force_unlock(malloc_zone_t *zone)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (isthreaded)
|
||||||
|
jemalloc_postfork();
|
||||||
|
}
|
||||||
|
|
||||||
|
malloc_zone_t *
|
||||||
|
create_zone(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
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 >= 6)
|
||||||
|
zone.memalign = zone_memalign;
|
||||||
|
zone.free_definite_size = zone_free_definite_size;
|
||||||
|
#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
|
||||||
|
|
||||||
|
return (&zone);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
ozone_size(malloc_zone_t *zone, void *ptr)
|
||||||
|
{
|
||||||
|
size_t ret;
|
||||||
|
|
||||||
|
ret = ivsalloc(ptr);
|
||||||
|
if (ret == 0)
|
||||||
|
ret = szone.size(zone, ptr);
|
||||||
|
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ozone_free(malloc_zone_t *zone, void *ptr)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (ivsalloc(ptr) != 0)
|
||||||
|
JEMALLOC_P(free)(ptr);
|
||||||
|
else {
|
||||||
|
size_t size = szone.size(zone, ptr);
|
||||||
|
if (size != 0)
|
||||||
|
(szone.free)(zone, ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
ozone_realloc(malloc_zone_t *zone, void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
size_t oldsize;
|
||||||
|
|
||||||
|
if (ptr == NULL)
|
||||||
|
return (JEMALLOC_P(malloc)(size));
|
||||||
|
|
||||||
|
oldsize = ivsalloc(ptr);
|
||||||
|
if (oldsize != 0)
|
||||||
|
return (JEMALLOC_P(realloc)(ptr, size));
|
||||||
|
else {
|
||||||
|
oldsize = szone.size(zone, ptr);
|
||||||
|
if (oldsize == 0)
|
||||||
|
return (JEMALLOC_P(malloc)(size));
|
||||||
|
else {
|
||||||
|
void *ret = JEMALLOC_P(malloc)(size);
|
||||||
|
if (ret != NULL) {
|
||||||
|
memcpy(ret, ptr, (oldsize < size) ? oldsize :
|
||||||
|
size);
|
||||||
|
(szone.free)(zone, ptr);
|
||||||
|
}
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned
|
||||||
|
ozone_batch_malloc(malloc_zone_t *zone, size_t size, void **results,
|
||||||
|
unsigned num_requested)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Don't bother implementing this interface, since it isn't required. */
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ozone_batch_free(malloc_zone_t *zone, void **to_be_freed, unsigned num)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++)
|
||||||
|
ozone_free(zone, to_be_freed[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (JEMALLOC_ZONE_VERSION >= 6)
|
||||||
|
static void
|
||||||
|
ozone_free_definite_size(malloc_zone_t *zone, void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (ivsalloc(ptr) != 0) {
|
||||||
|
assert(ivsalloc(ptr) == size);
|
||||||
|
JEMALLOC_P(free)(ptr);
|
||||||
|
} else {
|
||||||
|
assert(size == szone.size(zone, ptr));
|
||||||
|
szone.free_definite_size(zone, ptr, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
ozone_force_lock(malloc_zone_t *zone)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* jemalloc locking is taken care of by the normal jemalloc zone. */
|
||||||
|
szone.introspect->force_lock(zone);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ozone_force_unlock(malloc_zone_t *zone)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* jemalloc locking is taken care of by the normal jemalloc zone. */
|
||||||
|
szone.introspect->force_unlock(zone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Overlay the default scalable zone (szone) such that existing allocations are
|
||||||
|
* drained, and further allocations come from jemalloc. This is necessary
|
||||||
|
* because Core Foundation directly accesses and uses the szone before the
|
||||||
|
* jemalloc library is even loaded.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
szone2ozone(malloc_zone_t *zone)
|
||||||
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stash a copy of the original szone so that we can call its
|
||||||
|
* functions as needed. Note that the internally, the szone stores its
|
||||||
|
* bookkeeping data structures immediately following the malloc_zone_t
|
||||||
|
* header, so when calling szone functions, we need to pass a pointer
|
||||||
|
* to the original zone structure.
|
||||||
|
*/
|
||||||
|
memcpy(&szone, zone, sizeof(malloc_zone_t));
|
||||||
|
|
||||||
|
zone->size = (void *)ozone_size;
|
||||||
|
zone->malloc = (void *)zone_malloc;
|
||||||
|
zone->calloc = (void *)zone_calloc;
|
||||||
|
zone->valloc = (void *)zone_valloc;
|
||||||
|
zone->free = (void *)ozone_free;
|
||||||
|
zone->realloc = (void *)ozone_realloc;
|
||||||
|
zone->destroy = (void *)zone_destroy;
|
||||||
|
zone->zone_name = "jemalloc_ozone";
|
||||||
|
zone->batch_malloc = ozone_batch_malloc;
|
||||||
|
zone->batch_free = ozone_batch_free;
|
||||||
|
zone->introspect = &ozone_introspect;
|
||||||
|
zone->version = JEMALLOC_ZONE_VERSION;
|
||||||
|
#if (JEMALLOC_ZONE_VERSION >= 6)
|
||||||
|
zone->memalign = zone_memalign;
|
||||||
|
zone->free_definite_size = ozone_free_definite_size;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ozone_introspect.enumerator = NULL;
|
||||||
|
ozone_introspect.good_size = (void *)zone_good_size;
|
||||||
|
ozone_introspect.check = NULL;
|
||||||
|
ozone_introspect.print = NULL;
|
||||||
|
ozone_introspect.log = NULL;
|
||||||
|
ozone_introspect.force_lock = (void *)ozone_force_lock;
|
||||||
|
ozone_introspect.force_unlock = (void *)ozone_force_unlock;
|
||||||
|
ozone_introspect.statistics = NULL;
|
||||||
|
#if (JEMALLOC_ZONE_VERSION >= 6)
|
||||||
|
ozone_introspect.zone_locked = NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
142
test/allocated.c
Normal file
142
test/allocated.c
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define JEMALLOC_MANGLE
|
||||||
|
#include "jemalloc_test.h"
|
||||||
|
|
||||||
|
void *
|
||||||
|
thread_start(void *arg)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
void *p;
|
||||||
|
uint64_t a0, a1, d0, d1;
|
||||||
|
uint64_t *ap0, *ap1, *dp0, *dp1;
|
||||||
|
size_t sz, usize;
|
||||||
|
|
||||||
|
sz = sizeof(a0);
|
||||||
|
if ((err = JEMALLOC_P(mallctl)("thread.allocated", &a0, &sz, NULL,
|
||||||
|
0))) {
|
||||||
|
if (err == ENOENT) {
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
assert(false);
|
||||||
|
#endif
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "%s(): Error in mallctl(): %s\n", __func__,
|
||||||
|
strerror(err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
sz = sizeof(ap0);
|
||||||
|
if ((err = JEMALLOC_P(mallctl)("thread.allocatedp", &ap0, &sz, NULL,
|
||||||
|
0))) {
|
||||||
|
if (err == ENOENT) {
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
assert(false);
|
||||||
|
#endif
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "%s(): Error in mallctl(): %s\n", __func__,
|
||||||
|
strerror(err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
assert(*ap0 == a0);
|
||||||
|
|
||||||
|
sz = sizeof(d0);
|
||||||
|
if ((err = JEMALLOC_P(mallctl)("thread.deallocated", &d0, &sz, NULL,
|
||||||
|
0))) {
|
||||||
|
if (err == ENOENT) {
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
assert(false);
|
||||||
|
#endif
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "%s(): Error in mallctl(): %s\n", __func__,
|
||||||
|
strerror(err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
sz = sizeof(dp0);
|
||||||
|
if ((err = JEMALLOC_P(mallctl)("thread.deallocatedp", &dp0, &sz, NULL,
|
||||||
|
0))) {
|
||||||
|
if (err == ENOENT) {
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
assert(false);
|
||||||
|
#endif
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "%s(): Error in mallctl(): %s\n", __func__,
|
||||||
|
strerror(err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
assert(*dp0 == d0);
|
||||||
|
|
||||||
|
p = JEMALLOC_P(malloc)(1);
|
||||||
|
if (p == NULL) {
|
||||||
|
fprintf(stderr, "%s(): Error in malloc()\n", __func__);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
sz = sizeof(a1);
|
||||||
|
JEMALLOC_P(mallctl)("thread.allocated", &a1, &sz, NULL, 0);
|
||||||
|
sz = sizeof(ap1);
|
||||||
|
JEMALLOC_P(mallctl)("thread.allocatedp", &ap1, &sz, NULL, 0);
|
||||||
|
assert(*ap1 == a1);
|
||||||
|
assert(ap0 == ap1);
|
||||||
|
|
||||||
|
usize = JEMALLOC_P(malloc_usable_size)(p);
|
||||||
|
assert(a0 + usize <= a1);
|
||||||
|
|
||||||
|
JEMALLOC_P(free)(p);
|
||||||
|
|
||||||
|
sz = sizeof(d1);
|
||||||
|
JEMALLOC_P(mallctl)("thread.deallocated", &d1, &sz, NULL, 0);
|
||||||
|
sz = sizeof(dp1);
|
||||||
|
JEMALLOC_P(mallctl)("thread.deallocatedp", &dp1, &sz, NULL, 0);
|
||||||
|
assert(*dp1 == d1);
|
||||||
|
assert(dp0 == dp1);
|
||||||
|
|
||||||
|
assert(d0 + usize <= d1);
|
||||||
|
|
||||||
|
RETURN:
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
pthread_t thread;
|
||||||
|
|
||||||
|
fprintf(stderr, "Test begin\n");
|
||||||
|
|
||||||
|
thread_start(NULL);
|
||||||
|
|
||||||
|
if (pthread_create(&thread, NULL, thread_start, NULL)
|
||||||
|
!= 0) {
|
||||||
|
fprintf(stderr, "%s(): Error in pthread_create()\n", __func__);
|
||||||
|
ret = 1;
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
|
pthread_join(thread, (void *)&ret);
|
||||||
|
|
||||||
|
thread_start(NULL);
|
||||||
|
|
||||||
|
if (pthread_create(&thread, NULL, thread_start, NULL)
|
||||||
|
!= 0) {
|
||||||
|
fprintf(stderr, "%s(): Error in pthread_create()\n", __func__);
|
||||||
|
ret = 1;
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
|
pthread_join(thread, (void *)&ret);
|
||||||
|
|
||||||
|
thread_start(NULL);
|
||||||
|
|
||||||
|
RETURN:
|
||||||
|
fprintf(stderr, "Test end\n");
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
2
test/allocated.exp
Normal file
2
test/allocated.exp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Test begin
|
||||||
|
Test end
|
||||||
133
test/allocm.c
Normal file
133
test/allocm.c
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define JEMALLOC_MANGLE
|
||||||
|
#include "jemalloc_test.h"
|
||||||
|
|
||||||
|
#define CHUNK 0x400000
|
||||||
|
/* #define MAXALIGN ((size_t)0x80000000000LLU) */
|
||||||
|
#define MAXALIGN ((size_t)0x2000000LLU)
|
||||||
|
#define NITER 4
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
void *p;
|
||||||
|
size_t sz, alignment, total, tsz;
|
||||||
|
unsigned i;
|
||||||
|
void *ps[NITER];
|
||||||
|
|
||||||
|
fprintf(stderr, "Test begin\n");
|
||||||
|
|
||||||
|
sz = 0;
|
||||||
|
r = JEMALLOC_P(allocm)(&p, &sz, 42, 0);
|
||||||
|
if (r != ALLOCM_SUCCESS) {
|
||||||
|
fprintf(stderr, "Unexpected allocm() error\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
if (sz < 42)
|
||||||
|
fprintf(stderr, "Real size smaller than expected\n");
|
||||||
|
if (JEMALLOC_P(dallocm)(p, 0) != ALLOCM_SUCCESS)
|
||||||
|
fprintf(stderr, "Unexpected dallocm() error\n");
|
||||||
|
|
||||||
|
r = JEMALLOC_P(allocm)(&p, NULL, 42, 0);
|
||||||
|
if (r != ALLOCM_SUCCESS) {
|
||||||
|
fprintf(stderr, "Unexpected allocm() error\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
if (JEMALLOC_P(dallocm)(p, 0) != ALLOCM_SUCCESS)
|
||||||
|
fprintf(stderr, "Unexpected dallocm() error\n");
|
||||||
|
|
||||||
|
r = JEMALLOC_P(allocm)(&p, NULL, 42, ALLOCM_ZERO);
|
||||||
|
if (r != ALLOCM_SUCCESS) {
|
||||||
|
fprintf(stderr, "Unexpected allocm() error\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
if (JEMALLOC_P(dallocm)(p, 0) != ALLOCM_SUCCESS)
|
||||||
|
fprintf(stderr, "Unexpected dallocm() error\n");
|
||||||
|
|
||||||
|
#if LG_SIZEOF_PTR == 3
|
||||||
|
alignment = 0x8000000000000000LLU;
|
||||||
|
sz = 0x8000000000000000LLU;
|
||||||
|
#else
|
||||||
|
alignment = 0x80000000LU;
|
||||||
|
sz = 0x80000000LU;
|
||||||
|
#endif
|
||||||
|
r = JEMALLOC_P(allocm)(&p, NULL, sz, ALLOCM_ALIGN(alignment));
|
||||||
|
if (r == ALLOCM_SUCCESS) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Expected error for allocm(&p, %zu, 0x%x)\n",
|
||||||
|
sz, ALLOCM_ALIGN(alignment));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LG_SIZEOF_PTR == 3
|
||||||
|
alignment = 0x4000000000000000LLU;
|
||||||
|
sz = 0x8400000000000001LLU;
|
||||||
|
#else
|
||||||
|
alignment = 0x40000000LU;
|
||||||
|
sz = 0x84000001LU;
|
||||||
|
#endif
|
||||||
|
r = JEMALLOC_P(allocm)(&p, NULL, sz, ALLOCM_ALIGN(alignment));
|
||||||
|
if (r == ALLOCM_SUCCESS) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Expected error for allocm(&p, %zu, 0x%x)\n",
|
||||||
|
sz, ALLOCM_ALIGN(alignment));
|
||||||
|
}
|
||||||
|
|
||||||
|
alignment = 0x10LLU;
|
||||||
|
#if LG_SIZEOF_PTR == 3
|
||||||
|
sz = 0xfffffffffffffff0LLU;
|
||||||
|
#else
|
||||||
|
sz = 0xfffffff0LU;
|
||||||
|
#endif
|
||||||
|
r = JEMALLOC_P(allocm)(&p, NULL, sz, ALLOCM_ALIGN(alignment));
|
||||||
|
if (r == ALLOCM_SUCCESS) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Expected error for allocm(&p, %zu, 0x%x)\n",
|
||||||
|
sz, ALLOCM_ALIGN(alignment));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < NITER; i++)
|
||||||
|
ps[i] = NULL;
|
||||||
|
|
||||||
|
for (alignment = 8;
|
||||||
|
alignment <= MAXALIGN;
|
||||||
|
alignment <<= 1) {
|
||||||
|
total = 0;
|
||||||
|
fprintf(stderr, "Alignment: %zu\n", alignment);
|
||||||
|
for (sz = 1;
|
||||||
|
sz < 3 * alignment && sz < (1U << 31);
|
||||||
|
sz += (alignment >> (LG_SIZEOF_PTR-1)) - 1) {
|
||||||
|
for (i = 0; i < NITER; i++) {
|
||||||
|
r = JEMALLOC_P(allocm)(&ps[i], NULL, sz,
|
||||||
|
ALLOCM_ALIGN(alignment) | ALLOCM_ZERO);
|
||||||
|
if (r != ALLOCM_SUCCESS) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error for size %zu (0x%zx): %d\n",
|
||||||
|
sz, sz, r);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if ((uintptr_t)p & (alignment-1)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"%p inadequately aligned for"
|
||||||
|
" alignment: %zu\n", p, alignment);
|
||||||
|
}
|
||||||
|
JEMALLOC_P(sallocm)(ps[i], &tsz, 0);
|
||||||
|
total += tsz;
|
||||||
|
if (total >= (MAXALIGN << 1))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (i = 0; i < NITER; i++) {
|
||||||
|
if (ps[i] != NULL) {
|
||||||
|
JEMALLOC_P(dallocm)(ps[i], 0);
|
||||||
|
ps[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Test end\n");
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
25
test/allocm.exp
Normal file
25
test/allocm.exp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
Test begin
|
||||||
|
Alignment: 8
|
||||||
|
Alignment: 16
|
||||||
|
Alignment: 32
|
||||||
|
Alignment: 64
|
||||||
|
Alignment: 128
|
||||||
|
Alignment: 256
|
||||||
|
Alignment: 512
|
||||||
|
Alignment: 1024
|
||||||
|
Alignment: 2048
|
||||||
|
Alignment: 4096
|
||||||
|
Alignment: 8192
|
||||||
|
Alignment: 16384
|
||||||
|
Alignment: 32768
|
||||||
|
Alignment: 65536
|
||||||
|
Alignment: 131072
|
||||||
|
Alignment: 262144
|
||||||
|
Alignment: 524288
|
||||||
|
Alignment: 1048576
|
||||||
|
Alignment: 2097152
|
||||||
|
Alignment: 4194304
|
||||||
|
Alignment: 8388608
|
||||||
|
Alignment: 16777216
|
||||||
|
Alignment: 33554432
|
||||||
|
Test end
|
||||||
157
test/bitmap.c
Normal file
157
test/bitmap.c
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
#define JEMALLOC_MANGLE
|
||||||
|
#include "jemalloc_test.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Avoid using the assert() from jemalloc_internal.h, since it requires
|
||||||
|
* internal libjemalloc functionality.
|
||||||
|
* */
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Directly include the bitmap code, since it isn't exposed outside
|
||||||
|
* libjemalloc.
|
||||||
|
*/
|
||||||
|
#include "../src/bitmap.c"
|
||||||
|
|
||||||
|
#if (LG_BITMAP_MAXBITS > 12)
|
||||||
|
# define MAXBITS 4500
|
||||||
|
#else
|
||||||
|
# define MAXBITS (1U << LG_BITMAP_MAXBITS)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_bitmap_size(void)
|
||||||
|
{
|
||||||
|
size_t i, prev_size;
|
||||||
|
|
||||||
|
prev_size = 0;
|
||||||
|
for (i = 1; i <= MAXBITS; i++) {
|
||||||
|
size_t size = bitmap_size(i);
|
||||||
|
assert(size >= prev_size);
|
||||||
|
prev_size = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_bitmap_init(void)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 1; i <= MAXBITS; i++) {
|
||||||
|
bitmap_info_t binfo;
|
||||||
|
bitmap_info_init(&binfo, i);
|
||||||
|
{
|
||||||
|
size_t j;
|
||||||
|
bitmap_t bitmap[bitmap_info_ngroups(&binfo)];
|
||||||
|
bitmap_init(bitmap, &binfo);
|
||||||
|
|
||||||
|
for (j = 0; j < i; j++)
|
||||||
|
assert(bitmap_get(bitmap, &binfo, j) == false);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_bitmap_set(void)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 1; i <= MAXBITS; i++) {
|
||||||
|
bitmap_info_t binfo;
|
||||||
|
bitmap_info_init(&binfo, i);
|
||||||
|
{
|
||||||
|
size_t j;
|
||||||
|
bitmap_t bitmap[bitmap_info_ngroups(&binfo)];
|
||||||
|
bitmap_init(bitmap, &binfo);
|
||||||
|
|
||||||
|
for (j = 0; j < i; j++)
|
||||||
|
bitmap_set(bitmap, &binfo, j);
|
||||||
|
assert(bitmap_full(bitmap, &binfo));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_bitmap_unset(void)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 1; i <= MAXBITS; i++) {
|
||||||
|
bitmap_info_t binfo;
|
||||||
|
bitmap_info_init(&binfo, i);
|
||||||
|
{
|
||||||
|
size_t j;
|
||||||
|
bitmap_t bitmap[bitmap_info_ngroups(&binfo)];
|
||||||
|
bitmap_init(bitmap, &binfo);
|
||||||
|
|
||||||
|
for (j = 0; j < i; j++)
|
||||||
|
bitmap_set(bitmap, &binfo, j);
|
||||||
|
assert(bitmap_full(bitmap, &binfo));
|
||||||
|
for (j = 0; j < i; j++)
|
||||||
|
bitmap_unset(bitmap, &binfo, j);
|
||||||
|
for (j = 0; j < i; j++)
|
||||||
|
bitmap_set(bitmap, &binfo, j);
|
||||||
|
assert(bitmap_full(bitmap, &binfo));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_bitmap_sfu(void)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 1; i <= MAXBITS; i++) {
|
||||||
|
bitmap_info_t binfo;
|
||||||
|
bitmap_info_init(&binfo, i);
|
||||||
|
{
|
||||||
|
ssize_t j;
|
||||||
|
bitmap_t bitmap[bitmap_info_ngroups(&binfo)];
|
||||||
|
bitmap_init(bitmap, &binfo);
|
||||||
|
|
||||||
|
/* Iteratively set bits starting at the beginning. */
|
||||||
|
for (j = 0; j < i; j++)
|
||||||
|
assert(bitmap_sfu(bitmap, &binfo) == j);
|
||||||
|
assert(bitmap_full(bitmap, &binfo));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Iteratively unset bits starting at the end, and
|
||||||
|
* verify that bitmap_sfu() reaches the unset bits.
|
||||||
|
*/
|
||||||
|
for (j = i - 1; j >= 0; j--) {
|
||||||
|
bitmap_unset(bitmap, &binfo, j);
|
||||||
|
assert(bitmap_sfu(bitmap, &binfo) == j);
|
||||||
|
bitmap_unset(bitmap, &binfo, j);
|
||||||
|
}
|
||||||
|
assert(bitmap_get(bitmap, &binfo, 0) == false);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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(bitmap_sfu(bitmap, &binfo) == j);
|
||||||
|
bitmap_unset(bitmap, &binfo, j);
|
||||||
|
}
|
||||||
|
assert(bitmap_sfu(bitmap, &binfo) == i - 1);
|
||||||
|
assert(bitmap_full(bitmap, &binfo));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Test begin\n");
|
||||||
|
|
||||||
|
test_bitmap_size();
|
||||||
|
test_bitmap_init();
|
||||||
|
test_bitmap_set();
|
||||||
|
test_bitmap_unset();
|
||||||
|
test_bitmap_sfu();
|
||||||
|
|
||||||
|
fprintf(stderr, "Test end\n");
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
2
test/bitmap.exp
Normal file
2
test/bitmap.exp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Test begin
|
||||||
|
Test end
|
||||||
6
test/jemalloc_test.h.in
Normal file
6
test/jemalloc_test.h.in
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/*
|
||||||
|
* This header should be included by tests, rather than directly including
|
||||||
|
* jemalloc/jemalloc.h, because --with-install-suffix may cause the header to
|
||||||
|
* have a different name.
|
||||||
|
*/
|
||||||
|
#include "jemalloc/jemalloc@install_suffix@.h"
|
||||||
67
test/mremap.c
Normal file
67
test/mremap.c
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define JEMALLOC_MANGLE
|
||||||
|
#include "jemalloc_test.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
int ret, err;
|
||||||
|
size_t sz, lg_chunk, chunksize, i;
|
||||||
|
char *p, *q;
|
||||||
|
|
||||||
|
fprintf(stderr, "Test begin\n");
|
||||||
|
|
||||||
|
sz = sizeof(lg_chunk);
|
||||||
|
if ((err = JEMALLOC_P(mallctl)("opt.lg_chunk", &lg_chunk, &sz, NULL,
|
||||||
|
0))) {
|
||||||
|
assert(err != ENOENT);
|
||||||
|
fprintf(stderr, "%s(): Error in mallctl(): %s\n", __func__,
|
||||||
|
strerror(err));
|
||||||
|
ret = 1;
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
|
chunksize = ((size_t)1U) << lg_chunk;
|
||||||
|
|
||||||
|
p = (char *)malloc(chunksize);
|
||||||
|
if (p == NULL) {
|
||||||
|
fprintf(stderr, "malloc(%zu) --> %p\n", chunksize, p);
|
||||||
|
ret = 1;
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
|
memset(p, 'a', chunksize);
|
||||||
|
|
||||||
|
q = (char *)realloc(p, chunksize * 2);
|
||||||
|
if (q == NULL) {
|
||||||
|
fprintf(stderr, "realloc(%p, %zu) --> %p\n", p, chunksize * 2,
|
||||||
|
q);
|
||||||
|
ret = 1;
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
|
for (i = 0; i < chunksize; i++) {
|
||||||
|
assert(q[i] == 'a');
|
||||||
|
}
|
||||||
|
|
||||||
|
p = q;
|
||||||
|
|
||||||
|
q = (char *)realloc(p, chunksize);
|
||||||
|
if (q == NULL) {
|
||||||
|
fprintf(stderr, "realloc(%p, %zu) --> %p\n", p, chunksize, q);
|
||||||
|
ret = 1;
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
|
for (i = 0; i < chunksize; i++) {
|
||||||
|
assert(q[i] == 'a');
|
||||||
|
}
|
||||||
|
|
||||||
|
free(q);
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
RETURN:
|
||||||
|
fprintf(stderr, "Test end\n");
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
2
test/mremap.exp
Normal file
2
test/mremap.exp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Test begin
|
||||||
|
Test end
|
||||||
121
test/posix_memalign.c
Normal file
121
test/posix_memalign.c
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define JEMALLOC_MANGLE
|
||||||
|
#include "jemalloc_test.h"
|
||||||
|
|
||||||
|
#define CHUNK 0x400000
|
||||||
|
/* #define MAXALIGN ((size_t)0x80000000000LLU) */
|
||||||
|
#define MAXALIGN ((size_t)0x2000000LLU)
|
||||||
|
#define NITER 4
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
size_t alignment, size, total;
|
||||||
|
unsigned i;
|
||||||
|
int err;
|
||||||
|
void *p, *ps[NITER];
|
||||||
|
|
||||||
|
fprintf(stderr, "Test begin\n");
|
||||||
|
|
||||||
|
/* Test error conditions. */
|
||||||
|
for (alignment = 0; alignment < sizeof(void *); alignment++) {
|
||||||
|
err = JEMALLOC_P(posix_memalign)(&p, alignment, 1);
|
||||||
|
if (err != EINVAL) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Expected error for invalid alignment %zu\n",
|
||||||
|
alignment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (alignment = sizeof(size_t); alignment < MAXALIGN;
|
||||||
|
alignment <<= 1) {
|
||||||
|
err = JEMALLOC_P(posix_memalign)(&p, alignment + 1, 1);
|
||||||
|
if (err == 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Expected error for invalid alignment %zu\n",
|
||||||
|
alignment + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LG_SIZEOF_PTR == 3
|
||||||
|
alignment = 0x8000000000000000LLU;
|
||||||
|
size = 0x8000000000000000LLU;
|
||||||
|
#else
|
||||||
|
alignment = 0x80000000LU;
|
||||||
|
size = 0x80000000LU;
|
||||||
|
#endif
|
||||||
|
err = JEMALLOC_P(posix_memalign)(&p, alignment, size);
|
||||||
|
if (err == 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Expected error for posix_memalign(&p, %zu, %zu)\n",
|
||||||
|
alignment, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LG_SIZEOF_PTR == 3
|
||||||
|
alignment = 0x4000000000000000LLU;
|
||||||
|
size = 0x8400000000000001LLU;
|
||||||
|
#else
|
||||||
|
alignment = 0x40000000LU;
|
||||||
|
size = 0x84000001LU;
|
||||||
|
#endif
|
||||||
|
err = JEMALLOC_P(posix_memalign)(&p, alignment, size);
|
||||||
|
if (err == 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Expected error for posix_memalign(&p, %zu, %zu)\n",
|
||||||
|
alignment, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
alignment = 0x10LLU;
|
||||||
|
#if LG_SIZEOF_PTR == 3
|
||||||
|
size = 0xfffffffffffffff0LLU;
|
||||||
|
#else
|
||||||
|
size = 0xfffffff0LU;
|
||||||
|
#endif
|
||||||
|
err = JEMALLOC_P(posix_memalign)(&p, alignment, size);
|
||||||
|
if (err == 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Expected error for posix_memalign(&p, %zu, %zu)\n",
|
||||||
|
alignment, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < NITER; i++)
|
||||||
|
ps[i] = NULL;
|
||||||
|
|
||||||
|
for (alignment = 8;
|
||||||
|
alignment <= MAXALIGN;
|
||||||
|
alignment <<= 1) {
|
||||||
|
total = 0;
|
||||||
|
fprintf(stderr, "Alignment: %zu\n", alignment);
|
||||||
|
for (size = 1;
|
||||||
|
size < 3 * alignment && size < (1U << 31);
|
||||||
|
size += (alignment >> (LG_SIZEOF_PTR-1)) - 1) {
|
||||||
|
for (i = 0; i < NITER; i++) {
|
||||||
|
err = JEMALLOC_P(posix_memalign)(&ps[i],
|
||||||
|
alignment, size);
|
||||||
|
if (err) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error for size %zu (0x%zx): %s\n",
|
||||||
|
size, size, strerror(err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
total += JEMALLOC_P(malloc_usable_size)(ps[i]);
|
||||||
|
if (total >= (MAXALIGN << 1))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (i = 0; i < NITER; i++) {
|
||||||
|
if (ps[i] != NULL) {
|
||||||
|
JEMALLOC_P(free)(ps[i]);
|
||||||
|
ps[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Test end\n");
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
25
test/posix_memalign.exp
Normal file
25
test/posix_memalign.exp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
Test begin
|
||||||
|
Alignment: 8
|
||||||
|
Alignment: 16
|
||||||
|
Alignment: 32
|
||||||
|
Alignment: 64
|
||||||
|
Alignment: 128
|
||||||
|
Alignment: 256
|
||||||
|
Alignment: 512
|
||||||
|
Alignment: 1024
|
||||||
|
Alignment: 2048
|
||||||
|
Alignment: 4096
|
||||||
|
Alignment: 8192
|
||||||
|
Alignment: 16384
|
||||||
|
Alignment: 32768
|
||||||
|
Alignment: 65536
|
||||||
|
Alignment: 131072
|
||||||
|
Alignment: 262144
|
||||||
|
Alignment: 524288
|
||||||
|
Alignment: 1048576
|
||||||
|
Alignment: 2097152
|
||||||
|
Alignment: 4194304
|
||||||
|
Alignment: 8388608
|
||||||
|
Alignment: 16777216
|
||||||
|
Alignment: 33554432
|
||||||
|
Test end
|
||||||
117
test/rallocm.c
Normal file
117
test/rallocm.c
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define JEMALLOC_MANGLE
|
||||||
|
#include "jemalloc_test.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
void *p, *q;
|
||||||
|
size_t sz, tsz;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
fprintf(stderr, "Test begin\n");
|
||||||
|
|
||||||
|
r = JEMALLOC_P(allocm)(&p, &sz, 42, 0);
|
||||||
|
if (r != ALLOCM_SUCCESS) {
|
||||||
|
fprintf(stderr, "Unexpected allocm() error\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
q = p;
|
||||||
|
r = JEMALLOC_P(rallocm)(&q, &tsz, sz, 0, ALLOCM_NO_MOVE);
|
||||||
|
if (r != ALLOCM_SUCCESS)
|
||||||
|
fprintf(stderr, "Unexpected rallocm() error\n");
|
||||||
|
if (q != p)
|
||||||
|
fprintf(stderr, "Unexpected object move\n");
|
||||||
|
if (tsz != sz) {
|
||||||
|
fprintf(stderr, "Unexpected size change: %zu --> %zu\n",
|
||||||
|
sz, tsz);
|
||||||
|
}
|
||||||
|
|
||||||
|
q = p;
|
||||||
|
r = JEMALLOC_P(rallocm)(&q, &tsz, sz, 5, ALLOCM_NO_MOVE);
|
||||||
|
if (r != ALLOCM_SUCCESS)
|
||||||
|
fprintf(stderr, "Unexpected rallocm() error\n");
|
||||||
|
if (q != p)
|
||||||
|
fprintf(stderr, "Unexpected object move\n");
|
||||||
|
if (tsz != sz) {
|
||||||
|
fprintf(stderr, "Unexpected size change: %zu --> %zu\n",
|
||||||
|
sz, tsz);
|
||||||
|
}
|
||||||
|
|
||||||
|
q = p;
|
||||||
|
r = JEMALLOC_P(rallocm)(&q, &tsz, sz + 5, 0, ALLOCM_NO_MOVE);
|
||||||
|
if (r != ALLOCM_ERR_NOT_MOVED)
|
||||||
|
fprintf(stderr, "Unexpected rallocm() result\n");
|
||||||
|
if (q != p)
|
||||||
|
fprintf(stderr, "Unexpected object move\n");
|
||||||
|
if (tsz != sz) {
|
||||||
|
fprintf(stderr, "Unexpected size change: %zu --> %zu\n",
|
||||||
|
sz, tsz);
|
||||||
|
}
|
||||||
|
|
||||||
|
q = p;
|
||||||
|
r = JEMALLOC_P(rallocm)(&q, &tsz, sz + 5, 0, 0);
|
||||||
|
if (r != ALLOCM_SUCCESS)
|
||||||
|
fprintf(stderr, "Unexpected rallocm() error\n");
|
||||||
|
if (q == p)
|
||||||
|
fprintf(stderr, "Expected object move\n");
|
||||||
|
if (tsz == sz) {
|
||||||
|
fprintf(stderr, "Expected size change: %zu --> %zu\n",
|
||||||
|
sz, tsz);
|
||||||
|
}
|
||||||
|
p = q;
|
||||||
|
sz = tsz;
|
||||||
|
|
||||||
|
r = JEMALLOC_P(rallocm)(&q, &tsz, 8192, 0, 0);
|
||||||
|
if (r != ALLOCM_SUCCESS)
|
||||||
|
fprintf(stderr, "Unexpected rallocm() error\n");
|
||||||
|
if (q == p)
|
||||||
|
fprintf(stderr, "Expected object move\n");
|
||||||
|
if (tsz == sz) {
|
||||||
|
fprintf(stderr, "Expected size change: %zu --> %zu\n",
|
||||||
|
sz, tsz);
|
||||||
|
}
|
||||||
|
p = q;
|
||||||
|
sz = tsz;
|
||||||
|
|
||||||
|
r = JEMALLOC_P(rallocm)(&q, &tsz, 16384, 0, 0);
|
||||||
|
if (r != ALLOCM_SUCCESS)
|
||||||
|
fprintf(stderr, "Unexpected rallocm() error\n");
|
||||||
|
if (tsz == sz) {
|
||||||
|
fprintf(stderr, "Expected size change: %zu --> %zu\n",
|
||||||
|
sz, tsz);
|
||||||
|
}
|
||||||
|
p = q;
|
||||||
|
sz = tsz;
|
||||||
|
|
||||||
|
r = JEMALLOC_P(rallocm)(&q, &tsz, 8192, 0, ALLOCM_NO_MOVE);
|
||||||
|
if (r != ALLOCM_SUCCESS)
|
||||||
|
fprintf(stderr, "Unexpected rallocm() error\n");
|
||||||
|
if (q != p)
|
||||||
|
fprintf(stderr, "Unexpected object move\n");
|
||||||
|
if (tsz == sz) {
|
||||||
|
fprintf(stderr, "Expected size change: %zu --> %zu\n",
|
||||||
|
sz, tsz);
|
||||||
|
}
|
||||||
|
sz = tsz;
|
||||||
|
|
||||||
|
r = JEMALLOC_P(rallocm)(&q, &tsz, 16384, 0, ALLOCM_NO_MOVE);
|
||||||
|
if (r != ALLOCM_SUCCESS)
|
||||||
|
fprintf(stderr, "Unexpected rallocm() error\n");
|
||||||
|
if (q != p)
|
||||||
|
fprintf(stderr, "Unexpected object move\n");
|
||||||
|
if (tsz == sz) {
|
||||||
|
fprintf(stderr, "Expected size change: %zu --> %zu\n",
|
||||||
|
sz, tsz);
|
||||||
|
}
|
||||||
|
sz = tsz;
|
||||||
|
|
||||||
|
JEMALLOC_P(dallocm)(p, 0);
|
||||||
|
|
||||||
|
fprintf(stderr, "Test end\n");
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
2
test/rallocm.exp
Normal file
2
test/rallocm.exp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Test begin
|
||||||
|
Test end
|
||||||
92
test/thread_arena.c
Normal file
92
test/thread_arena.c
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#define JEMALLOC_MANGLE
|
||||||
|
#include "jemalloc_test.h"
|
||||||
|
|
||||||
|
#define NTHREADS 10
|
||||||
|
|
||||||
|
void *
|
||||||
|
thread_start(void *arg)
|
||||||
|
{
|
||||||
|
unsigned main_arena_ind = *(unsigned *)arg;
|
||||||
|
void *p;
|
||||||
|
unsigned arena_ind;
|
||||||
|
size_t size;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
p = JEMALLOC_P(malloc)(1);
|
||||||
|
if (p == NULL) {
|
||||||
|
fprintf(stderr, "%s(): Error in malloc()\n", __func__);
|
||||||
|
return (void *)1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = sizeof(arena_ind);
|
||||||
|
if ((err = JEMALLOC_P(mallctl)("thread.arena", &arena_ind, &size,
|
||||||
|
&main_arena_ind, sizeof(main_arena_ind)))) {
|
||||||
|
fprintf(stderr, "%s(): Error in mallctl(): %s\n", __func__,
|
||||||
|
strerror(err));
|
||||||
|
return (void *)1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = sizeof(arena_ind);
|
||||||
|
if ((err = JEMALLOC_P(mallctl)("thread.arena", &arena_ind, &size, NULL,
|
||||||
|
0))) {
|
||||||
|
fprintf(stderr, "%s(): Error in mallctl(): %s\n", __func__,
|
||||||
|
strerror(err));
|
||||||
|
return (void *)1;
|
||||||
|
}
|
||||||
|
assert(arena_ind == main_arena_ind);
|
||||||
|
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
void *p;
|
||||||
|
unsigned arena_ind;
|
||||||
|
size_t size;
|
||||||
|
int err;
|
||||||
|
pthread_t threads[NTHREADS];
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
fprintf(stderr, "Test begin\n");
|
||||||
|
|
||||||
|
p = JEMALLOC_P(malloc)(1);
|
||||||
|
if (p == NULL) {
|
||||||
|
fprintf(stderr, "%s(): Error in malloc()\n", __func__);
|
||||||
|
ret = 1;
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = sizeof(arena_ind);
|
||||||
|
if ((err = JEMALLOC_P(mallctl)("thread.arena", &arena_ind, &size, NULL,
|
||||||
|
0))) {
|
||||||
|
fprintf(stderr, "%s(): Error in mallctl(): %s\n", __func__,
|
||||||
|
strerror(err));
|
||||||
|
ret = 1;
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < NTHREADS; i++) {
|
||||||
|
if (pthread_create(&threads[i], NULL, thread_start,
|
||||||
|
(void *)&arena_ind) != 0) {
|
||||||
|
fprintf(stderr, "%s(): Error in pthread_create()\n",
|
||||||
|
__func__);
|
||||||
|
ret = 1;
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < NTHREADS; i++)
|
||||||
|
pthread_join(threads[i], (void *)&ret);
|
||||||
|
|
||||||
|
RETURN:
|
||||||
|
fprintf(stderr, "Test end\n");
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
2
test/thread_arena.exp
Normal file
2
test/thread_arena.exp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Test begin
|
||||||
|
Test end
|
||||||
Reference in New Issue
Block a user