mirror of
https://github.com/jemalloc/jemalloc.git
synced 2026-07-22 04:03:11 +00:00
Compare commits
138 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5bdbae57ee | ||
|
|
c67e4fdc71 | ||
|
|
a9076c9483 | ||
|
|
46405e670f | ||
|
|
749c2a0ab6 | ||
|
|
a507004d29 | ||
|
|
745e30b157 | ||
|
|
b493ce22a4 | ||
|
|
183ba50c19 | ||
|
|
0cdd42eb32 | ||
|
|
41b954ed36 | ||
|
|
04ca1efe35 | ||
|
|
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 |
38
.gitignore
vendored
38
.gitignore
vendored
@@ -1,15 +1,23 @@
|
|||||||
/jemalloc/autom4te.cache/
|
/autom4te.cache/
|
||||||
/jemalloc/config.stamp
|
/config.stamp
|
||||||
/jemalloc/config.log
|
/config.log
|
||||||
/jemalloc/config.status
|
/config.status
|
||||||
/jemalloc/configure
|
/configure
|
||||||
/jemalloc/doc/jemalloc.3
|
/doc/html.xsl
|
||||||
/jemalloc/lib/
|
/doc/manpages.xsl
|
||||||
/jemalloc/Makefile
|
/doc/jemalloc.xml
|
||||||
/jemalloc/src/internal/jemalloc_internal\.h
|
/doc/jemalloc.html
|
||||||
/jemalloc/src/internal/mtrgraph_defs\.h
|
/doc/jemalloc.3
|
||||||
/jemalloc/src/internal/mtrplay_defs\.h
|
/lib/
|
||||||
/jemalloc/src/jemalloc\.h
|
/Makefile
|
||||||
/jemalloc/src/jemalloc_defs\.h
|
/include/jemalloc/internal/jemalloc_internal\.h
|
||||||
/jemalloc/src/*.[od]
|
/include/jemalloc/jemalloc\.h
|
||||||
/jemalloc/VERSION
|
/include/jemalloc/jemalloc_defs\.h
|
||||||
|
/test/jemalloc_test\.h
|
||||||
|
/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:
|
||||||
235
ChangeLog
Normal file
235
ChangeLog
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
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.3 (August 31, 2011)
|
||||||
|
|
||||||
|
This version fixes numerous bugs related to heap profiling.
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
- Fix a prof-related race condition. This bug could cause memory corruption,
|
||||||
|
but only occurred in non-default configurations (prof_accum:false).
|
||||||
|
- Fix off-by-one backtracing issues (make sure that prof_alloc_prep() is
|
||||||
|
excluded from backtraces).
|
||||||
|
- Fix a prof-related bug in realloc() (only triggered by OOM errors).
|
||||||
|
- Fix prof-related bugs in allocm() and rallocm().
|
||||||
|
- Fix prof_tdata_cleanup() for --disable-tls builds.
|
||||||
|
- Fix a relative include path, to fix objdir builds.
|
||||||
|
|
||||||
|
* 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,64 @@ 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', 'E',
|
Enable heap profiling and leak detection functionality. See the "opt.prof"
|
||||||
'F', '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>
|
--with-static-libunwind=<libunwind.a>
|
||||||
Statically link against the specified libunwind.a rather than dynamically
|
Statically link against the specified libunwind.a rather than dynamically
|
||||||
@@ -72,8 +99,8 @@ any of the following arguments (not a definitive list) to 'configure':
|
|||||||
|
|
||||||
--disable-tcache
|
--disable-tcache
|
||||||
Disable thread-specific caches for small objects. Objects are cached and
|
Disable thread-specific caches for small objects. Objects are cached and
|
||||||
released in bulk, thus reducing the total number of mutex operations. Use
|
released in bulk, thus reducing the total number of mutex operations. See
|
||||||
the 'H', 'G', and 'M' 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
|
||||||
@@ -85,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
|
||||||
@@ -116,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. Note 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:
|
||||||
@@ -156,7 +186,7 @@ To install only parts of jemalloc, use the following targets:
|
|||||||
install_bin
|
install_bin
|
||||||
install_include
|
install_include
|
||||||
install_lib
|
install_lib
|
||||||
install_man
|
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:
|
||||||
|
|
||||||
@@ -179,8 +209,8 @@ MANDIR="?"
|
|||||||
Use this as the installation prefix for man pages.
|
Use this as the installation prefix for man pages.
|
||||||
|
|
||||||
DESTDIR="?"
|
DESTDIR="?"
|
||||||
Prepend DESTDIR to INCLUDEDIR, LIBDIR, and MANDIR. This is useful when
|
Prepend DESTDIR to INCLUDEDIR, LIBDIR, DATADIR, and MANDIR. This is useful
|
||||||
installing to a different path than was specified via --prefix.
|
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.
|
||||||
@@ -213,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/
|
||||||
File diff suppressed because it is too large
Load Diff
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,6 +80,19 @@ 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
|
||||||
@@ -119,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=""
|
||||||
@@ -144,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.
|
||||||
@@ -166,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*)
|
||||||
@@ -191,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*)
|
||||||
@@ -210,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)])],
|
||||||
@@ -245,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])],
|
||||||
@@ -263,17 +317,29 @@ AC_ARG_WITH([install_suffix],
|
|||||||
install_suffix="$INSTALL_SUFFIX"
|
install_suffix="$INSTALL_SUFFIX"
|
||||||
AC_SUBST([install_suffix])
|
AC_SUBST([install_suffix])
|
||||||
|
|
||||||
cfgoutputs_in="${srcroot}Makefile.in ${srcroot}doc/jemalloc.3.in"
|
cfgoutputs_in="${srcroot}Makefile.in"
|
||||||
|
cfgoutputs_in="${cfgoutputs_in} ${srcroot}doc/html.xsl.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/jemalloc.h.in"
|
||||||
cfgoutputs_in="${cfgoutputs_in} ${srcroot}include/jemalloc/internal/jemalloc_internal.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="${srcroot}include/jemalloc/jemalloc_defs.h.in"
|
cfghdrs_in="${srcroot}include/jemalloc/jemalloc_defs.h.in"
|
||||||
|
|
||||||
@@ -281,6 +347,23 @@ 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])],
|
||||||
@@ -294,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])
|
||||||
|
|
||||||
@@ -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,17 +423,12 @@ fi
|
|||||||
],
|
],
|
||||||
[enable_prof="0"]
|
[enable_prof="0"]
|
||||||
)
|
)
|
||||||
AC_ARG_ENABLE([prof-libgcc],
|
if test "x$enable_prof" = "x1" ; then
|
||||||
[AS_HELP_STRING([--disable-prof-libgcc],
|
backtrace_method=""
|
||||||
[Do not use libgcc for backtracing])],
|
|
||||||
[if test "x$enable_prof_libgcc" = "xno" ; then
|
|
||||||
enable_prof_libgcc="0"
|
|
||||||
else
|
else
|
||||||
enable_prof_libgcc="1"
|
backtrace_method="N/A"
|
||||||
fi
|
fi
|
||||||
],
|
|
||||||
[enable_prof_libgcc="1"]
|
|
||||||
)
|
|
||||||
AC_ARG_ENABLE([prof-libunwind],
|
AC_ARG_ENABLE([prof-libunwind],
|
||||||
[AS_HELP_STRING([--enable-prof-libunwind], [Use libunwind for backtracing])],
|
[AS_HELP_STRING([--enable-prof-libunwind], [Use libunwind for backtracing])],
|
||||||
[if test "x$enable_prof_libunwind" = "xno" ; then
|
[if test "x$enable_prof_libunwind" = "xno" ; then
|
||||||
@@ -379,7 +452,89 @@ else
|
|||||||
fi,
|
fi,
|
||||||
LUNWIND="-lunwind"
|
LUNWIND="-lunwind"
|
||||||
)
|
)
|
||||||
dnl Finish prof-related definitions below, once TLS configuration is done.
|
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],
|
||||||
|
[AS_HELP_STRING([--disable-prof-libgcc],
|
||||||
|
[Do not use libgcc for backtracing])],
|
||||||
|
[if test "x$enable_prof_libgcc" = "xno" ; then
|
||||||
|
enable_prof_libgcc="0"
|
||||||
|
else
|
||||||
|
enable_prof_libgcc="1"
|
||||||
|
fi
|
||||||
|
],
|
||||||
|
[enable_prof_libgcc="1"]
|
||||||
|
)
|
||||||
|
if test "x$backtrace_method" = "x" -a "x$enable_prof_libgcc" = "x1" \
|
||||||
|
-a "x$GCC" = "xyes" ; then
|
||||||
|
AC_CHECK_HEADERS([unwind.h], , [enable_prof_libgcc="0"])
|
||||||
|
AC_CHECK_LIB([gcc], [_Unwind_Backtrace], [LIBS="$LIBS -lgcc"], [enable_prof_libgcc="0"])
|
||||||
|
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
|
||||||
|
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
|
||||||
|
],
|
||||||
|
[enable_prof_gcc="1"]
|
||||||
|
)
|
||||||
|
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],
|
||||||
@@ -396,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],
|
||||||
@@ -417,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],
|
||||||
@@ -434,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],
|
||||||
@@ -456,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],
|
||||||
@@ -478,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],
|
||||||
@@ -500,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],
|
||||||
@@ -522,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],
|
||||||
@@ -578,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}'`
|
||||||
@@ -647,69 +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"])
|
|
||||||
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
|
|
||||||
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 ============================================================================
|
||||||
@@ -740,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}])
|
||||||
@@ -753,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}])
|
||||||
@@ -768,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>
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
#ifdef JEMALLOC_TINY
|
#ifdef JEMALLOC_TINY
|
||||||
/* Smallest size class to support. */
|
/* Smallest size class to support. */
|
||||||
# define LG_TINY_MIN LG_SIZEOF_PTR
|
# define LG_TINY_MIN LG_SIZEOF_PTR
|
||||||
|
# define TINY_MIN (1U << LG_TINY_MIN)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -45,9 +46,10 @@
|
|||||||
* point is implicitly RUN_BFP bits to the left.
|
* 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
|
* 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
|
* honored for some/all object sizes, since when heap profiling is enabled
|
||||||
* per object (plus a constant). This constraint is relaxed (ignored) for runs
|
* there is one pointer of header overhead per object (plus a constant). This
|
||||||
* that are so small that the per-region overhead is greater than:
|
* 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))
|
* (RUN_MAX_OVRHD / (reg_size << (3+RUN_BFP))
|
||||||
*/
|
*/
|
||||||
@@ -56,6 +58,10 @@
|
|||||||
#define RUN_MAX_OVRHD 0x0000003dU
|
#define RUN_MAX_OVRHD 0x0000003dU
|
||||||
#define RUN_MAX_OVRHD_RELAX 0x00001800U
|
#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:
|
* The minimum ratio of active:dirty pages per arena is computed as:
|
||||||
*
|
*
|
||||||
@@ -69,6 +75,7 @@
|
|||||||
typedef struct arena_chunk_map_s arena_chunk_map_t;
|
typedef struct arena_chunk_map_s arena_chunk_map_t;
|
||||||
typedef struct arena_chunk_s arena_chunk_t;
|
typedef struct arena_chunk_s arena_chunk_t;
|
||||||
typedef struct arena_run_s arena_run_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_bin_s arena_bin_t;
|
||||||
typedef struct arena_s arena_t;
|
typedef struct arena_s arena_t;
|
||||||
|
|
||||||
@@ -105,7 +112,7 @@ struct arena_chunk_map_s {
|
|||||||
* Run address (or size) and various flags are stored together. The bit
|
* Run address (or size) and various flags are stored together. The bit
|
||||||
* layout looks like (assuming 32-bit system):
|
* layout looks like (assuming 32-bit system):
|
||||||
*
|
*
|
||||||
* ???????? ???????? ????---- ----dzla
|
* ???????? ???????? ????---- ----dula
|
||||||
*
|
*
|
||||||
* ? : Unallocated: Run address for first/last pages, unset for internal
|
* ? : Unallocated: Run address for first/last pages, unset for internal
|
||||||
* pages.
|
* pages.
|
||||||
@@ -113,7 +120,7 @@ struct arena_chunk_map_s {
|
|||||||
* Large: Run size for first page, unset for trailing pages.
|
* Large: Run size for first page, unset for trailing pages.
|
||||||
* - : Unused.
|
* - : Unused.
|
||||||
* d : dirty?
|
* d : dirty?
|
||||||
* z : zeroed?
|
* u : unzeroed?
|
||||||
* l : large?
|
* l : large?
|
||||||
* a : allocated?
|
* a : allocated?
|
||||||
*
|
*
|
||||||
@@ -121,38 +128,38 @@ struct arena_chunk_map_s {
|
|||||||
*
|
*
|
||||||
* p : run page offset
|
* p : run page offset
|
||||||
* s : run size
|
* s : run size
|
||||||
* c : size class (used only if prof_promote is true)
|
* c : (binind+1) for size class (used only if prof_promote is true)
|
||||||
* x : don't care
|
* x : don't care
|
||||||
* - : 0
|
* - : 0
|
||||||
* + : 1
|
* + : 1
|
||||||
* [DZLA] : bit set
|
* [DULA] : bit set
|
||||||
* [dzla] : bit unset
|
* [dula] : bit unset
|
||||||
*
|
*
|
||||||
* Unallocated (clean):
|
* Unallocated (clean):
|
||||||
* ssssssss ssssssss ssss---- ----dz--
|
* ssssssss ssssssss ssss---- ----du-a
|
||||||
* xxxxxxxx xxxxxxxx xxxx---- -----Zxx
|
* xxxxxxxx xxxxxxxx xxxx---- -----Uxx
|
||||||
* ssssssss ssssssss ssss---- ----dZ--
|
* ssssssss ssssssss ssss---- ----dU-a
|
||||||
*
|
*
|
||||||
* Unallocated (dirty):
|
* Unallocated (dirty):
|
||||||
* ssssssss ssssssss ssss---- ----D---
|
* ssssssss ssssssss ssss---- ----D--a
|
||||||
* xxxxxxxx xxxxxxxx xxxx---- ----xxxx
|
* xxxxxxxx xxxxxxxx xxxx---- ----xxxx
|
||||||
* ssssssss ssssssss ssss---- ----D---
|
* ssssssss ssssssss ssss---- ----D--a
|
||||||
*
|
*
|
||||||
* Small:
|
* Small:
|
||||||
* pppppppp pppppppp pppp---- ----d--a
|
* pppppppp pppppppp pppp---- ----d--A
|
||||||
* pppppppp pppppppp pppp---- -------a
|
* pppppppp pppppppp pppp---- -------A
|
||||||
* pppppppp pppppppp pppp---- ----d--a
|
* pppppppp pppppppp pppp---- ----d--A
|
||||||
*
|
*
|
||||||
* Large:
|
* Large:
|
||||||
* ssssssss ssssssss ssss++++ ++++D-la
|
* ssssssss ssssssss ssss---- ----D-LA
|
||||||
* xxxxxxxx xxxxxxxx xxxx---- ----xxxx
|
* xxxxxxxx xxxxxxxx xxxx---- ----xxxx
|
||||||
* -------- -------- -------- ----D-la
|
* -------- -------- -------- ----D-LA
|
||||||
*
|
*
|
||||||
* Large (sampled, size <= PAGE_SIZE):
|
* Large (sampled, size <= PAGE_SIZE):
|
||||||
* ssssssss ssssssss sssscccc ccccD-la
|
* ssssssss ssssssss sssscccc ccccD-LA
|
||||||
*
|
*
|
||||||
* Large (not sampled, size == PAGE_SIZE):
|
* Large (not sampled, size == PAGE_SIZE):
|
||||||
* ssssssss ssssssss ssss++++ ++++D-la
|
* ssssssss ssssssss ssss---- ----D-LA
|
||||||
*/
|
*/
|
||||||
size_t bits;
|
size_t bits;
|
||||||
#ifdef JEMALLOC_PROF
|
#ifdef JEMALLOC_PROF
|
||||||
@@ -161,7 +168,7 @@ struct arena_chunk_map_s {
|
|||||||
#endif
|
#endif
|
||||||
#define CHUNK_MAP_FLAGS_MASK ((size_t)0xfU)
|
#define CHUNK_MAP_FLAGS_MASK ((size_t)0xfU)
|
||||||
#define CHUNK_MAP_DIRTY ((size_t)0x8U)
|
#define CHUNK_MAP_DIRTY ((size_t)0x8U)
|
||||||
#define CHUNK_MAP_ZEROED ((size_t)0x4U)
|
#define CHUNK_MAP_UNZEROED ((size_t)0x4U)
|
||||||
#define CHUNK_MAP_LARGE ((size_t)0x2U)
|
#define CHUNK_MAP_LARGE ((size_t)0x2U)
|
||||||
#define CHUNK_MAP_ALLOCATED ((size_t)0x1U)
|
#define CHUNK_MAP_ALLOCATED ((size_t)0x1U)
|
||||||
#define CHUNK_MAP_KEY CHUNK_MAP_ALLOCATED
|
#define CHUNK_MAP_KEY CHUNK_MAP_ALLOCATED
|
||||||
@@ -187,7 +194,12 @@ struct arena_chunk_s {
|
|||||||
/* Number of dirty pages. */
|
/* Number of dirty pages. */
|
||||||
size_t ndirty;
|
size_t ndirty;
|
||||||
|
|
||||||
/* Map of pages within chunk that keeps track of free/large/small. */
|
/*
|
||||||
|
* 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. */
|
arena_chunk_map_t map[1]; /* Dynamically sized. */
|
||||||
};
|
};
|
||||||
typedef rb_tree(arena_chunk_t) arena_chunk_tree_t;
|
typedef rb_tree(arena_chunk_t) arena_chunk_tree_t;
|
||||||
@@ -201,16 +213,52 @@ struct arena_run_s {
|
|||||||
/* Bin this run is associated with. */
|
/* Bin this run is associated with. */
|
||||||
arena_bin_t *bin;
|
arena_bin_t *bin;
|
||||||
|
|
||||||
/* Stack of available freed regions, or NULL. */
|
/* Index of next region that has never been allocated, or nregs. */
|
||||||
void *avail;
|
uint32_t nextind;
|
||||||
|
|
||||||
/* Next region that has never been allocated, or run boundary. */
|
|
||||||
void *next;
|
|
||||||
|
|
||||||
/* Number of free regions in run. */
|
/* Number of free regions in run. */
|
||||||
unsigned nfree;
|
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 {
|
struct arena_bin_s {
|
||||||
/*
|
/*
|
||||||
* All operations on runcur, runs, and stats require that lock be
|
* All operations on runcur, runs, and stats require that lock be
|
||||||
@@ -235,26 +283,6 @@ struct arena_bin_s {
|
|||||||
*/
|
*/
|
||||||
arena_run_tree_t runs;
|
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;
|
|
||||||
|
|
||||||
#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;
|
|
||||||
|
|
||||||
#ifdef JEMALLOC_STATS
|
#ifdef JEMALLOC_STATS
|
||||||
/* Bin statistics. */
|
/* Bin statistics. */
|
||||||
malloc_bin_stats_t stats;
|
malloc_bin_stats_t stats;
|
||||||
@@ -271,8 +299,18 @@ struct arena_s {
|
|||||||
unsigned ind;
|
unsigned ind;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All non-bin-related operations on this arena require that lock be
|
* Number of threads currently assigned to this arena. This field is
|
||||||
* locked.
|
* 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;
|
malloc_mutex_t lock;
|
||||||
|
|
||||||
@@ -342,45 +380,35 @@ struct arena_s {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* bins is used to store trees of free regions of the following sizes,
|
* bins is used to store trees of free regions of the following sizes,
|
||||||
* assuming a 16-byte quantum, 4 KiB page size, and default
|
* assuming a 64-bit system with 16-byte quantum, 4 KiB page size, and
|
||||||
* JEMALLOC_OPTIONS.
|
* default MALLOC_CONF.
|
||||||
*
|
*
|
||||||
* bins[i] | size |
|
* bins[i] | size |
|
||||||
* --------+--------+
|
* --------+--------+
|
||||||
* 0 | 2 |
|
* 0 | 8 |
|
||||||
* 1 | 4 |
|
|
||||||
* 2 | 8 |
|
|
||||||
* --------+--------+
|
* --------+--------+
|
||||||
* 3 | 16 |
|
* 1 | 16 |
|
||||||
* 4 | 32 |
|
* 2 | 32 |
|
||||||
* 5 | 48 |
|
* 3 | 48 |
|
||||||
* : :
|
* : :
|
||||||
* 8 | 96 |
|
* 6 | 96 |
|
||||||
* 9 | 112 |
|
* 7 | 112 |
|
||||||
* 10 | 128 |
|
* 8 | 128 |
|
||||||
* --------+--------+
|
* --------+--------+
|
||||||
* 11 | 192 |
|
* 9 | 192 |
|
||||||
* 12 | 256 |
|
* 10 | 256 |
|
||||||
* 13 | 320 |
|
* 11 | 320 |
|
||||||
* 14 | 384 |
|
* 12 | 384 |
|
||||||
* 15 | 448 |
|
* 13 | 448 |
|
||||||
* 16 | 512 |
|
* 14 | 512 |
|
||||||
* --------+--------+
|
* --------+--------+
|
||||||
* 17 | 768 |
|
* 15 | 768 |
|
||||||
* 18 | 1024 |
|
* 16 | 1024 |
|
||||||
* 19 | 1280 |
|
* 17 | 1280 |
|
||||||
* : :
|
* : :
|
||||||
* 27 | 3328 |
|
* 25 | 3328 |
|
||||||
* 28 | 3584 |
|
* 26 | 3584 |
|
||||||
* 29 | 3840 |
|
* 27 | 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. */
|
arena_bin_t bins[1]; /* Dynamically sized. */
|
||||||
@@ -392,8 +420,16 @@ struct arena_s {
|
|||||||
|
|
||||||
extern size_t opt_lg_qspace_max;
|
extern size_t opt_lg_qspace_max;
|
||||||
extern size_t opt_lg_cspace_max;
|
extern size_t opt_lg_cspace_max;
|
||||||
extern ssize_t opt_lg_dirty_mult;
|
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;
|
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. */
|
/* Various bin-related settings. */
|
||||||
#ifdef JEMALLOC_TINY /* Number of (2^n)-spaced tiny bins. */
|
#ifdef JEMALLOC_TINY /* Number of (2^n)-spaced tiny bins. */
|
||||||
@@ -416,8 +452,12 @@ extern size_t sspace_min;
|
|||||||
extern size_t sspace_max;
|
extern size_t sspace_max;
|
||||||
#define small_maxclass sspace_max
|
#define small_maxclass sspace_max
|
||||||
|
|
||||||
#define nlclasses (chunk_npages - arena_chunk_header_npages)
|
#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
|
#ifdef JEMALLOC_TCACHE
|
||||||
void arena_tcache_fill_small(arena_t *arena, tcache_bin_t *tbin,
|
void arena_tcache_fill_small(arena_t *arena, tcache_bin_t *tbin,
|
||||||
size_t binind
|
size_t binind
|
||||||
@@ -426,20 +466,15 @@ void arena_tcache_fill_small(arena_t *arena, tcache_bin_t *tbin,
|
|||||||
# endif
|
# endif
|
||||||
);
|
);
|
||||||
#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_small(arena_t *arena, size_t size, bool zero);
|
||||||
void *arena_malloc_large(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_malloc(size_t size, bool zero);
|
||||||
void *arena_palloc(arena_t *arena, size_t alignment, size_t size,
|
void *arena_palloc(arena_t *arena, size_t size, size_t alloc_size,
|
||||||
size_t alloc_size);
|
size_t alignment, bool zero);
|
||||||
size_t arena_salloc(const void *ptr);
|
size_t arena_salloc(const void *ptr);
|
||||||
#ifdef JEMALLOC_PROF
|
#ifdef JEMALLOC_PROF
|
||||||
void arena_prof_promoted(const void *ptr, size_t size);
|
void arena_prof_promoted(const void *ptr, size_t size);
|
||||||
size_t arena_salloc_demote(const void *ptr);
|
size_t arena_salloc_demote(const void *ptr);
|
||||||
prof_ctx_t *arena_prof_ctx_get(const void *ptr);
|
|
||||||
void arena_prof_ctx_set(const void *ptr, prof_ctx_t *ctx);
|
|
||||||
#endif
|
#endif
|
||||||
void arena_dalloc_bin(arena_t *arena, arena_chunk_t *chunk, void *ptr,
|
void arena_dalloc_bin(arena_t *arena, arena_chunk_t *chunk, void *ptr,
|
||||||
arena_chunk_map_t *mapelm);
|
arena_chunk_map_t *mapelm);
|
||||||
@@ -449,7 +484,10 @@ void arena_stats_merge(arena_t *arena, size_t *nactive, size_t *ndirty,
|
|||||||
arena_stats_t *astats, malloc_bin_stats_t *bstats,
|
arena_stats_t *astats, malloc_bin_stats_t *bstats,
|
||||||
malloc_large_stats_t *lstats);
|
malloc_large_stats_t *lstats);
|
||||||
#endif
|
#endif
|
||||||
void *arena_ralloc(void *ptr, size_t size, size_t oldsize);
|
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_new(arena_t *arena, unsigned ind);
|
||||||
bool arena_boot(void);
|
bool arena_boot(void);
|
||||||
|
|
||||||
@@ -458,10 +496,171 @@ bool arena_boot(void);
|
|||||||
#ifdef JEMALLOC_H_INLINES
|
#ifdef JEMALLOC_H_INLINES
|
||||||
|
|
||||||
#ifndef JEMALLOC_ENABLE_INLINE
|
#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);
|
void arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_))
|
#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
|
JEMALLOC_INLINE void
|
||||||
arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr)
|
arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr)
|
||||||
{
|
{
|
||||||
@@ -469,13 +668,13 @@ arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr)
|
|||||||
arena_chunk_map_t *mapelm;
|
arena_chunk_map_t *mapelm;
|
||||||
|
|
||||||
assert(arena != NULL);
|
assert(arena != NULL);
|
||||||
assert(arena->magic == ARENA_MAGIC);
|
dassert(arena->magic == ARENA_MAGIC);
|
||||||
assert(chunk->arena == arena);
|
assert(chunk->arena == arena);
|
||||||
assert(ptr != NULL);
|
assert(ptr != NULL);
|
||||||
assert(CHUNK_ADDR2BASE(ptr) != ptr);
|
assert(CHUNK_ADDR2BASE(ptr) != ptr);
|
||||||
|
|
||||||
pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT);
|
pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT;
|
||||||
mapelm = &chunk->map[pageind];
|
mapelm = &chunk->map[pageind-map_bias];
|
||||||
assert((mapelm->bits & CHUNK_MAP_ALLOCATED) != 0);
|
assert((mapelm->bits & CHUNK_MAP_ALLOCATED) != 0);
|
||||||
if ((mapelm->bits & CHUNK_MAP_LARGE) == 0) {
|
if ((mapelm->bits & CHUNK_MAP_LARGE) == 0) {
|
||||||
/* Small allocation. */
|
/* Small allocation. */
|
||||||
@@ -492,11 +691,18 @@ arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr)
|
|||||||
run = (arena_run_t *)((uintptr_t)chunk +
|
run = (arena_run_t *)((uintptr_t)chunk +
|
||||||
(uintptr_t)((pageind - (mapelm->bits >>
|
(uintptr_t)((pageind - (mapelm->bits >>
|
||||||
PAGE_SHIFT)) << PAGE_SHIFT));
|
PAGE_SHIFT)) << PAGE_SHIFT));
|
||||||
assert(run->magic == ARENA_RUN_MAGIC);
|
dassert(run->magic == ARENA_RUN_MAGIC);
|
||||||
assert(((uintptr_t)ptr - ((uintptr_t)run +
|
|
||||||
(uintptr_t)run->bin->reg0_offset)) %
|
|
||||||
run->bin->reg_size == 0);
|
|
||||||
bin = run->bin;
|
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);
|
malloc_mutex_lock(&bin->lock);
|
||||||
arena_dalloc_bin(arena, chunk, ptr, mapelm);
|
arena_dalloc_bin(arena, chunk, ptr, mapelm);
|
||||||
malloc_mutex_unlock(&bin->lock);
|
malloc_mutex_unlock(&bin->lock);
|
||||||
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);
|
||||||
|
|
||||||
@@ -13,6 +13,8 @@ void *chunk_alloc_mmap(size_t size);
|
|||||||
void *chunk_alloc_mmap_noreserve(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,6 +29,7 @@ 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
|
||||||
@@ -82,9 +83,9 @@ 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_write("<jemalloc>: Invalid xmallctl(\""); \
|
malloc_write("<jemalloc>: Failure in xmallctl(\""); \
|
||||||
malloc_write(name); \
|
malloc_write(name); \
|
||||||
malloc_write("\", ...) call\n"); \
|
malloc_write("\", ...)\n"); \
|
||||||
abort(); \
|
abort(); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
@@ -92,9 +93,9 @@ bool ctl_boot(void);
|
|||||||
#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_write( \
|
malloc_write( \
|
||||||
"<jemalloc>: Invalid xmallctlnametomib(\""); \
|
"<jemalloc>: Failure in xmallctlnametomib(\""); \
|
||||||
malloc_write(name); \
|
malloc_write(name); \
|
||||||
malloc_write("\", ...) call\n"); \
|
malloc_write("\", ...)\n"); \
|
||||||
abort(); \
|
abort(); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
@@ -103,7 +104,7 @@ bool ctl_boot(void);
|
|||||||
if (JEMALLOC_P(mallctlbymib)(mib, miblen, oldp, oldlenp, newp, \
|
if (JEMALLOC_P(mallctlbymib)(mib, miblen, oldp, oldlenp, newp, \
|
||||||
newlen) != 0) { \
|
newlen) != 0) { \
|
||||||
malloc_write( \
|
malloc_write( \
|
||||||
"<jemalloc>: Invalid xmallctlbymib() call\n"); \
|
"<jemalloc>: Failure in xmallctlbymib()\n"); \
|
||||||
abort(); \
|
abort(); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
@@ -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,9 +20,12 @@ 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_ctx_t *huge_prof_ctx_get(const void *ptr);
|
prof_ctx_t *huge_prof_ctx_get(const void *ptr);
|
||||||
@@ -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 "jemalloc/internal/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
|
||||||
@@ -42,14 +61,15 @@ extern void (*JEMALLOC_P(malloc_message))(void *wcbopaque, const char *s);
|
|||||||
* 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_write("<jemalloc>: "); \
|
malloc_write("<jemalloc>: "); \
|
||||||
malloc_write(__FILE__); \
|
malloc_write(__FILE__); \
|
||||||
malloc_write(":"); \
|
malloc_write(":"); \
|
||||||
malloc_write(umax2s(__LINE__, 10, line_buf)); \
|
malloc_write(u2s(__LINE__, 10, line_buf)); \
|
||||||
malloc_write(": Failed assertion: "); \
|
malloc_write(": Failed assertion: "); \
|
||||||
malloc_write("\""); \
|
malloc_write("\""); \
|
||||||
malloc_write(#e); \
|
malloc_write(#e); \
|
||||||
@@ -57,8 +77,15 @@ extern void (*JEMALLOC_P(malloc_message))(void *wcbopaque, const char *s);
|
|||||||
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
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -77,6 +104,8 @@ extern void (*JEMALLOC_P(malloc_message))(void *wcbopaque, const char *s);
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
#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
|
||||||
@@ -92,8 +121,8 @@ extern void (*JEMALLOC_P(malloc_message))(void *wcbopaque, const char *s);
|
|||||||
# 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__
|
||||||
@@ -131,12 +160,19 @@ extern void (*JEMALLOC_P(malloc_message))(void *wcbopaque, const char *s);
|
|||||||
#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.
|
||||||
@@ -159,6 +195,16 @@ extern void (*JEMALLOC_P(malloc_message))(void *wcbopaque, const char *s);
|
|||||||
#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
|
||||||
@@ -173,6 +219,7 @@ extern void (*JEMALLOC_P(malloc_message))(void *wcbopaque, const char *s);
|
|||||||
#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"
|
||||||
@@ -181,32 +228,50 @@ extern void (*JEMALLOC_P(malloc_message))(void *wcbopaque, const char *s);
|
|||||||
#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
|
||||||
@@ -224,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;
|
||||||
@@ -235,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.
|
||||||
@@ -249,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"
|
||||||
@@ -285,11 +398,144 @@ arena_t *choose_arena_hard(void);
|
|||||||
#include "jemalloc/internal/huge.h"
|
#include "jemalloc/internal/huge.h"
|
||||||
|
|
||||||
#ifndef JEMALLOC_ENABLE_INLINE
|
#ifndef JEMALLOC_ENABLE_INLINE
|
||||||
|
size_t pow2_ceil(size_t x);
|
||||||
|
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);
|
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.
|
||||||
@@ -310,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_))
|
||||||
@@ -408,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);
|
||||||
@@ -513,7 +674,7 @@ 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
|
#ifdef JEMALLOC_PROF
|
||||||
ret = arena_salloc_demote(ptr);
|
ret = arena_salloc_demote(ptr);
|
||||||
@@ -526,21 +687,18 @@ isalloc(const void *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)
|
||||||
@@ -553,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 */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@@ -34,17 +45,26 @@ 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
|
JEMALLOC_INLINE bool
|
||||||
malloc_mutex_trylock(malloc_mutex_t *mutex)
|
malloc_mutex_trylock(malloc_mutex_t *mutex)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (isthreaded)
|
if (isthreaded) {
|
||||||
|
#ifdef JEMALLOC_OSSPIN
|
||||||
|
return (OSSpinLockTry(mutex) == false);
|
||||||
|
#else
|
||||||
return (pthread_mutex_trylock(mutex) != 0);
|
return (pthread_mutex_trylock(mutex) != 0);
|
||||||
else
|
#endif
|
||||||
|
} else
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,8 +72,13 @@ 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
|
||||||
|
|
||||||
195
include/jemalloc/internal/private_namespace.h
Normal file
195
include/jemalloc/internal/private_namespace.h
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
#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_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)
|
||||||
547
include/jemalloc/internal/prof.h
Normal file
547
include/jemalloc/internal/prof.h
Normal file
@@ -0,0 +1,547 @@
|
|||||||
|
#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
|
||||||
|
|
||||||
|
#define PROF_ALLOC_PREP(nignore, size, ret) do { \
|
||||||
|
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) { \
|
||||||
|
ret = NULL; \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
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; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#ifndef JEMALLOC_ENABLE_INLINE
|
||||||
|
void prof_sample_threshold_update(prof_tdata_t *prof_tdata);
|
||||||
|
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_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 */
|
||||||
|
/******************************************************************************/
|
||||||
@@ -154,7 +154,11 @@ 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
|
||||||
|
extern size_t stats_cactive;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char *u2s(uint64_t x, unsigned base, char *s);
|
||||||
#ifdef JEMALLOC_STATS
|
#ifdef JEMALLOC_STATS
|
||||||
void malloc_cprintf(void (*write)(void *, const char *), void *cbopaque,
|
void malloc_cprintf(void (*write)(void *, const char *), void *cbopaque,
|
||||||
const char *format, ...) JEMALLOC_ATTR(format(printf, 3, 4));
|
const char *format, ...) JEMALLOC_ATTR(format(printf, 3, 4));
|
||||||
@@ -166,9 +170,38 @@ void stats_print(void (*write)(void *, const char *), void *cbopaque,
|
|||||||
|
|
||||||
#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 */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
#ifdef JEMALLOC_H_TYPES
|
#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_bin_s tcache_bin_t;
|
||||||
typedef struct tcache_s tcache_t;
|
typedef struct tcache_s tcache_t;
|
||||||
|
|
||||||
@@ -17,7 +18,7 @@ typedef struct tcache_s tcache_t;
|
|||||||
/* Number of cache slots for large size classes. */
|
/* Number of cache slots for large size classes. */
|
||||||
#define TCACHE_NSLOTS_LARGE 20
|
#define TCACHE_NSLOTS_LARGE 20
|
||||||
|
|
||||||
/* (1U << opt_lg_tcache_maxclass) is used to compute tcache_maxclass. */
|
/* (1U << opt_lg_tcache_max) is used to compute tcache_maxclass. */
|
||||||
#define LG_TCACHE_MAXCLASS_DEFAULT 15
|
#define LG_TCACHE_MAXCLASS_DEFAULT 15
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -32,15 +33,22 @@ typedef struct tcache_s tcache_t;
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
#ifdef JEMALLOC_H_STRUCTS
|
#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 {
|
struct tcache_bin_s {
|
||||||
# ifdef JEMALLOC_STATS
|
# ifdef JEMALLOC_STATS
|
||||||
tcache_bin_stats_t tstats;
|
tcache_bin_stats_t tstats;
|
||||||
# endif
|
# endif
|
||||||
unsigned low_water; /* Min # cached since last GC. */
|
int low_water; /* Min # cached since last GC. */
|
||||||
unsigned high_water; /* Max # cached since last GC. */
|
unsigned lg_fill_div; /* Fill (ncached_max >> lg_fill_div). */
|
||||||
unsigned ncached; /* # of cached objects. */
|
unsigned ncached; /* # of cached objects. */
|
||||||
unsigned ncached_max; /* Upper limit on ncached. */
|
void **avail; /* Stack of available objects. */
|
||||||
void *avail; /* Chain of available objects. */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tcache_s {
|
struct tcache_s {
|
||||||
@@ -54,6 +62,12 @@ struct tcache_s {
|
|||||||
unsigned ev_cnt; /* Event count since incremental GC. */
|
unsigned ev_cnt; /* Event count since incremental GC. */
|
||||||
unsigned next_gc_bin; /* Next bin to GC. */
|
unsigned next_gc_bin; /* Next bin to GC. */
|
||||||
tcache_bin_t tbins[1]; /* Dynamically sized. */
|
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 */
|
#endif /* JEMALLOC_H_STRUCTS */
|
||||||
@@ -61,12 +75,27 @@ struct tcache_s {
|
|||||||
#ifdef JEMALLOC_H_EXTERNS
|
#ifdef JEMALLOC_H_EXTERNS
|
||||||
|
|
||||||
extern bool opt_tcache;
|
extern bool opt_tcache;
|
||||||
extern ssize_t opt_lg_tcache_maxclass;
|
extern ssize_t opt_lg_tcache_max;
|
||||||
extern ssize_t opt_lg_tcache_gc_sweep;
|
extern ssize_t opt_lg_tcache_gc_sweep;
|
||||||
|
|
||||||
|
extern tcache_bin_info_t *tcache_bin_info;
|
||||||
|
|
||||||
/* Map of thread-specific caches. */
|
/* Map of thread-specific caches. */
|
||||||
|
#ifndef NO_TLS
|
||||||
extern __thread tcache_t *tcache_tls
|
extern __thread tcache_t *tcache_tls
|
||||||
JEMALLOC_ATTR(tls_model("initial-exec"));
|
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
|
* Number of tcache bins. There are nbins small-object bins, plus 0 or more
|
||||||
@@ -97,7 +126,7 @@ void tcache_destroy(tcache_t *tcache);
|
|||||||
#ifdef JEMALLOC_STATS
|
#ifdef JEMALLOC_STATS
|
||||||
void tcache_stats_merge(tcache_t *tcache, arena_t *arena);
|
void tcache_stats_merge(tcache_t *tcache, arena_t *arena);
|
||||||
#endif
|
#endif
|
||||||
void tcache_boot(void);
|
bool tcache_boot(void);
|
||||||
|
|
||||||
#endif /* JEMALLOC_H_EXTERNS */
|
#endif /* JEMALLOC_H_EXTERNS */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@@ -122,14 +151,23 @@ tcache_get(void)
|
|||||||
if ((isthreaded & opt_tcache) == false)
|
if ((isthreaded & opt_tcache) == false)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
tcache = tcache_tls;
|
tcache = TCACHE_GET();
|
||||||
if ((uintptr_t)tcache <= (uintptr_t)1) {
|
if ((uintptr_t)tcache <= (uintptr_t)2) {
|
||||||
if (tcache == NULL) {
|
if (tcache == NULL) {
|
||||||
tcache = tcache_create(choose_arena());
|
tcache = tcache_create(choose_arena());
|
||||||
if (tcache == NULL)
|
if (tcache == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
} else
|
} 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 (NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (tcache);
|
return (tcache);
|
||||||
@@ -147,6 +185,7 @@ tcache_event(tcache_t *tcache)
|
|||||||
if (tcache->ev_cnt == tcache_gc_incr) {
|
if (tcache->ev_cnt == tcache_gc_incr) {
|
||||||
size_t binind = tcache->next_gc_bin;
|
size_t binind = tcache->next_gc_bin;
|
||||||
tcache_bin_t *tbin = &tcache->tbins[binind];
|
tcache_bin_t *tbin = &tcache->tbins[binind];
|
||||||
|
tcache_bin_info_t *tbin_info = &tcache_bin_info[binind];
|
||||||
|
|
||||||
if (tbin->low_water > 0) {
|
if (tbin->low_water > 0) {
|
||||||
/*
|
/*
|
||||||
@@ -170,9 +209,22 @@ tcache_event(tcache_t *tcache)
|
|||||||
#endif
|
#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;
|
tbin->low_water = tbin->ncached;
|
||||||
tbin->high_water = tbin->ncached;
|
|
||||||
|
|
||||||
tcache->next_gc_bin++;
|
tcache->next_gc_bin++;
|
||||||
if (tcache->next_gc_bin == nhbins)
|
if (tcache->next_gc_bin == nhbins)
|
||||||
@@ -186,13 +238,14 @@ tcache_alloc_easy(tcache_bin_t *tbin)
|
|||||||
{
|
{
|
||||||
void *ret;
|
void *ret;
|
||||||
|
|
||||||
if (tbin->ncached == 0)
|
if (tbin->ncached == 0) {
|
||||||
|
tbin->low_water = -1;
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
}
|
||||||
tbin->ncached--;
|
tbin->ncached--;
|
||||||
if (tbin->ncached < tbin->low_water)
|
if ((int)tbin->ncached < tbin->low_water)
|
||||||
tbin->low_water = tbin->ncached;
|
tbin->low_water = tbin->ncached;
|
||||||
ret = tbin->avail;
|
ret = tbin->avail[tbin->ncached];
|
||||||
tbin->avail = *(void **)ret;
|
|
||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,7 +256,7 @@ tcache_alloc_small(tcache_t *tcache, size_t size, bool zero)
|
|||||||
size_t binind;
|
size_t binind;
|
||||||
tcache_bin_t *tbin;
|
tcache_bin_t *tbin;
|
||||||
|
|
||||||
binind = small_size2bin[size];
|
binind = SMALL_SIZE2BIN(size);
|
||||||
assert(binind < nbins);
|
assert(binind < nbins);
|
||||||
tbin = &tcache->tbins[binind];
|
tbin = &tcache->tbins[binind];
|
||||||
ret = tcache_alloc_easy(tbin);
|
ret = tcache_alloc_easy(tbin);
|
||||||
@@ -212,7 +265,7 @@ tcache_alloc_small(tcache_t *tcache, size_t size, bool zero)
|
|||||||
if (ret == NULL)
|
if (ret == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
assert(arena_salloc(ret) == tcache->arena->bins[binind].reg_size);
|
assert(arena_salloc(ret) == arena_bin_info[binind].reg_size);
|
||||||
|
|
||||||
if (zero == false) {
|
if (zero == false) {
|
||||||
#ifdef JEMALLOC_FILL
|
#ifdef JEMALLOC_FILL
|
||||||
@@ -228,7 +281,7 @@ tcache_alloc_small(tcache_t *tcache, size_t size, bool zero)
|
|||||||
tbin->tstats.nrequests++;
|
tbin->tstats.nrequests++;
|
||||||
#endif
|
#endif
|
||||||
#ifdef JEMALLOC_PROF
|
#ifdef JEMALLOC_PROF
|
||||||
tcache->prof_accumbytes += tcache->arena->bins[binind].reg_size;
|
tcache->prof_accumbytes += arena_bin_info[binind].reg_size;
|
||||||
#endif
|
#endif
|
||||||
tcache_event(tcache);
|
tcache_event(tcache);
|
||||||
return (ret);
|
return (ret);
|
||||||
@@ -258,9 +311,9 @@ tcache_alloc_large(tcache_t *tcache, size_t size, bool zero)
|
|||||||
} else {
|
} else {
|
||||||
#ifdef JEMALLOC_PROF
|
#ifdef JEMALLOC_PROF
|
||||||
arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ret);
|
arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ret);
|
||||||
size_t pageind = (unsigned)(((uintptr_t)ret - (uintptr_t)chunk)
|
size_t pageind = (((uintptr_t)ret - (uintptr_t)chunk) >>
|
||||||
>> PAGE_SHIFT);
|
PAGE_SHIFT);
|
||||||
chunk->map[pageind].bits |= CHUNK_MAP_CLASS_MASK;
|
chunk->map[pageind-map_bias].bits &= ~CHUNK_MAP_CLASS_MASK;
|
||||||
#endif
|
#endif
|
||||||
if (zero == false) {
|
if (zero == false) {
|
||||||
#ifdef JEMALLOC_FILL
|
#ifdef JEMALLOC_FILL
|
||||||
@@ -292,6 +345,7 @@ tcache_dalloc_small(tcache_t *tcache, void *ptr)
|
|||||||
arena_run_t *run;
|
arena_run_t *run;
|
||||||
arena_bin_t *bin;
|
arena_bin_t *bin;
|
||||||
tcache_bin_t *tbin;
|
tcache_bin_t *tbin;
|
||||||
|
tcache_bin_info_t *tbin_info;
|
||||||
size_t pageind, binind;
|
size_t pageind, binind;
|
||||||
arena_chunk_map_t *mapelm;
|
arena_chunk_map_t *mapelm;
|
||||||
|
|
||||||
@@ -299,11 +353,11 @@ tcache_dalloc_small(tcache_t *tcache, void *ptr)
|
|||||||
|
|
||||||
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
||||||
arena = chunk->arena;
|
arena = chunk->arena;
|
||||||
pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT);
|
pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT;
|
||||||
mapelm = &chunk->map[pageind];
|
mapelm = &chunk->map[pageind-map_bias];
|
||||||
run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)((pageind -
|
run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)((pageind -
|
||||||
(mapelm->bits >> PAGE_SHIFT)) << PAGE_SHIFT));
|
(mapelm->bits >> PAGE_SHIFT)) << PAGE_SHIFT));
|
||||||
assert(run->magic == ARENA_RUN_MAGIC);
|
dassert(run->magic == ARENA_RUN_MAGIC);
|
||||||
bin = run->bin;
|
bin = run->bin;
|
||||||
binind = ((uintptr_t)bin - (uintptr_t)&arena->bins) /
|
binind = ((uintptr_t)bin - (uintptr_t)&arena->bins) /
|
||||||
sizeof(arena_bin_t);
|
sizeof(arena_bin_t);
|
||||||
@@ -311,23 +365,22 @@ tcache_dalloc_small(tcache_t *tcache, void *ptr)
|
|||||||
|
|
||||||
#ifdef JEMALLOC_FILL
|
#ifdef JEMALLOC_FILL
|
||||||
if (opt_junk)
|
if (opt_junk)
|
||||||
memset(ptr, 0x5a, bin->reg_size);
|
memset(ptr, 0x5a, arena_bin_info[binind].reg_size);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
tbin = &tcache->tbins[binind];
|
tbin = &tcache->tbins[binind];
|
||||||
if (tbin->ncached == tbin->ncached_max) {
|
tbin_info = &tcache_bin_info[binind];
|
||||||
tcache_bin_flush_small(tbin, binind, (tbin->ncached_max >> 1)
|
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))
|
#if (defined(JEMALLOC_STATS) || defined(JEMALLOC_PROF))
|
||||||
, tcache
|
, tcache
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
assert(tbin->ncached < tbin->ncached_max);
|
assert(tbin->ncached < tbin_info->ncached_max);
|
||||||
*(void **)ptr = tbin->avail;
|
tbin->avail[tbin->ncached] = ptr;
|
||||||
tbin->avail = ptr;
|
|
||||||
tbin->ncached++;
|
tbin->ncached++;
|
||||||
if (tbin->ncached > tbin->high_water)
|
|
||||||
tbin->high_water = tbin->ncached;
|
|
||||||
|
|
||||||
tcache_event(tcache);
|
tcache_event(tcache);
|
||||||
}
|
}
|
||||||
@@ -339,7 +392,7 @@ tcache_dalloc_large(tcache_t *tcache, void *ptr, size_t size)
|
|||||||
arena_chunk_t *chunk;
|
arena_chunk_t *chunk;
|
||||||
size_t pageind, binind;
|
size_t pageind, binind;
|
||||||
tcache_bin_t *tbin;
|
tcache_bin_t *tbin;
|
||||||
arena_chunk_map_t *mapelm;
|
tcache_bin_info_t *tbin_info;
|
||||||
|
|
||||||
assert((size & PAGE_MASK) == 0);
|
assert((size & PAGE_MASK) == 0);
|
||||||
assert(arena_salloc(ptr) > small_maxclass);
|
assert(arena_salloc(ptr) > small_maxclass);
|
||||||
@@ -347,8 +400,7 @@ tcache_dalloc_large(tcache_t *tcache, void *ptr, size_t size)
|
|||||||
|
|
||||||
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
||||||
arena = chunk->arena;
|
arena = chunk->arena;
|
||||||
pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT);
|
pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT;
|
||||||
mapelm = &chunk->map[pageind];
|
|
||||||
binind = nbins + (size >> PAGE_SHIFT) - 1;
|
binind = nbins + (size >> PAGE_SHIFT) - 1;
|
||||||
|
|
||||||
#ifdef JEMALLOC_FILL
|
#ifdef JEMALLOC_FILL
|
||||||
@@ -357,19 +409,18 @@ tcache_dalloc_large(tcache_t *tcache, void *ptr, size_t size)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
tbin = &tcache->tbins[binind];
|
tbin = &tcache->tbins[binind];
|
||||||
if (tbin->ncached == tbin->ncached_max) {
|
tbin_info = &tcache_bin_info[binind];
|
||||||
tcache_bin_flush_large(tbin, binind, (tbin->ncached_max >> 1)
|
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))
|
#if (defined(JEMALLOC_STATS) || defined(JEMALLOC_PROF))
|
||||||
, tcache
|
, tcache
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
assert(tbin->ncached < tbin->ncached_max);
|
assert(tbin->ncached < tbin_info->ncached_max);
|
||||||
*(void **)ptr = tbin->avail;
|
tbin->avail[tbin->ncached] = ptr;
|
||||||
tbin->avail = ptr;
|
|
||||||
tbin->ncached++;
|
tbin->ncached++;
|
||||||
if (tbin->ncached > tbin->high_water)
|
|
||||||
tbin->high_water = tbin->ncached;
|
|
||||||
|
|
||||||
tcache_event(tcache);
|
tcache_event(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,7 +19,20 @@ 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)
|
||||||
|
#if LG_SIZEOF_PTR == 2
|
||||||
|
#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 *);
|
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);
|
||||||
@@ -36,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
|
||||||
@@ -13,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
|
||||||
@@ -31,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.
|
||||||
@@ -49,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.
|
||||||
@@ -92,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,148 +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.
|
|
||||||
DESTDIR =
|
|
||||||
BINDIR := $(DESTDIR)@BINDIR@
|
|
||||||
INCLUDEDIR := $(DESTDIR)@INCLUDEDIR@
|
|
||||||
LIBDIR := $(DESTDIR)@LIBDIR@
|
|
||||||
MANDIR := $(DESTDIR)@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.
|
|
||||||
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/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)"
|
|
||||||
|
|
||||||
%.so : %.so.$(REV)
|
|
||||||
@mkdir -p $(@D)
|
|
||||||
ln -sf $(<F) $@
|
|
||||||
|
|
||||||
@objroot@lib/libjemalloc@install_suffix@.so.$(REV) : $(CSRCS:@srcroot@%.c=@objroot@%.o)
|
|
||||||
@mkdir -p $(@D)
|
|
||||||
$(CC) -shared -Wl,-soname,$(@F) -o $@ $+ $(LDFLAGS) $(LIBS)
|
|
||||||
|
|
||||||
@objroot@lib/libjemalloc@install_suffix@_pic.a : $(CSRCS:@srcroot@%.c=@objroot@%.o)
|
|
||||||
@mkdir -p $(@D)
|
|
||||||
ar crus $@ $+
|
|
||||||
|
|
||||||
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)
|
|
||||||
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_man:
|
|
||||||
install -d $(MANDIR)/man3
|
|
||||||
@for m in $(MAN3); do \
|
|
||||||
echo "install -m 644 $$m $(MANDIR)/man3"; \
|
|
||||||
install -m 644 $$m $(MANDIR)/man3; \
|
|
||||||
done
|
|
||||||
|
|
||||||
install: install_bin install_include install_lib install_man
|
|
||||||
|
|
||||||
check:
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f $(CSRCS:@srcroot@%.c=@objroot@%.o)
|
|
||||||
rm -f $(CSRCS:@srcroot@%.c=@objroot@%.d)
|
|
||||||
rm -f $(DSOS)
|
|
||||||
|
|
||||||
distclean: clean
|
|
||||||
rm -rf @objroot@autom4te.cache
|
|
||||||
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 -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
|
|
||||||
|
|
||||||
@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
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
jemalloc is a general-purpose scalable concurrent malloc(3) implementation.
|
|
||||||
This distribution is a stand-alone "portable" implementation that currently
|
|
||||||
targets only Linux. 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.
|
|
||||||
|
|
||||||
URL: http://www.canonware.com/jemalloc/
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,174 +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 {
|
|
||||||
/* Associated backtrace. */
|
|
||||||
prof_bt_t *bt;
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
/*
|
|
||||||
* 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_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;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If true, promote small sampled objects to large objects, since small run
|
|
||||||
* headers do not have embedded profile context pointers.
|
|
||||||
*/
|
|
||||||
extern bool prof_promote;
|
|
||||||
|
|
||||||
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_ctx_t *prof_ctx_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_ctx_t *old_ctx);
|
|
||||||
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 */
|
|
||||||
File diff suppressed because it is too large
Load Diff
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,26 +6,30 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 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, bool noreserve);
|
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, bool noreserve);
|
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 *chunk_alloc_mmap_internal(size_t size, bool noreserve);
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@@ -54,9 +58,9 @@ pages_map(void *addr, size_t size, bool noreserve)
|
|||||||
* 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_write("<jemalloc>: Error in munmap(): ");
|
malloc_write("<jemalloc>: Error in munmap(): ");
|
||||||
malloc_write(buf);
|
malloc_write(buf);
|
||||||
malloc_write("\n");
|
malloc_write("\n");
|
||||||
@@ -76,9 +80,9 @@ 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_write("<jemalloc>: Error in munmap(): ");
|
malloc_write("<jemalloc>: Error in munmap(): ");
|
||||||
malloc_write(buf);
|
malloc_write(buf);
|
||||||
malloc_write("\n");
|
malloc_write("\n");
|
||||||
@@ -128,7 +132,7 @@ chunk_alloc_mmap_slow(size_t size, bool unaligned, bool noreserve)
|
|||||||
* method.
|
* method.
|
||||||
*/
|
*/
|
||||||
if (unaligned == false)
|
if (unaligned == false)
|
||||||
mmap_unaligned = false;
|
MMAP_UNALIGNED_SET(false);
|
||||||
|
|
||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
@@ -166,7 +170,7 @@ chunk_alloc_mmap_internal(size_t size, bool noreserve)
|
|||||||
* 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, noreserve);
|
ret = pages_map(NULL, size, noreserve);
|
||||||
@@ -175,7 +179,7 @@ chunk_alloc_mmap_internal(size_t size, bool noreserve)
|
|||||||
|
|
||||||
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, noreserve) == NULL) {
|
chunksize - offset, noreserve) == NULL) {
|
||||||
@@ -184,7 +188,8 @@ chunk_alloc_mmap_internal(size_t size, bool noreserve)
|
|||||||
* 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, noreserve);
|
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);
|
||||||
@@ -201,13 +206,15 @@ chunk_alloc_mmap_internal(size_t size, bool noreserve)
|
|||||||
void *
|
void *
|
||||||
chunk_alloc_mmap(size_t size)
|
chunk_alloc_mmap(size_t size)
|
||||||
{
|
{
|
||||||
return chunk_alloc_mmap_internal(size, false);
|
|
||||||
|
return (chunk_alloc_mmap_internal(size, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
chunk_alloc_mmap_noreserve(size_t size)
|
chunk_alloc_mmap_noreserve(size_t size)
|
||||||
{
|
{
|
||||||
return chunk_alloc_mmap_internal(size, true);
|
|
||||||
|
return (chunk_alloc_mmap_internal(size, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -216,3 +223,17 @@ 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);
|
||||||
}
|
}
|
||||||
@@ -294,9 +312,10 @@ 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));
|
|
||||||
|
buferror(errno, buf, sizeof(buf));
|
||||||
malloc_write(
|
malloc_write(
|
||||||
"<jemalloc>: Error in mmap(..., MAP_FIXED, ...): ");
|
"<jemalloc>: Error in mmap(..., MAP_FIXED, ...): ");
|
||||||
malloc_write(buf);
|
malloc_write(buf);
|
||||||
@@ -304,7 +323,7 @@ chunk_swap_enable(const int *fds, unsigned nfds, bool prezeroed)
|
|||||||
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_write("<jemalloc>: Error in munmap(): ");
|
malloc_write("<jemalloc>: Error in munmap(): ");
|
||||||
malloc_write(buf);
|
malloc_write(buf);
|
||||||
malloc_write("\n");
|
malloc_write("\n");
|
||||||
@@ -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;
|
||||||
@@ -4,6 +4,13 @@
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* Data. */
|
/* Data. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ctl_mtx protects the following:
|
||||||
|
* - ctl_stats.*
|
||||||
|
* - opt_prof_active
|
||||||
|
* - swap_enabled
|
||||||
|
* - swap_prezeroed
|
||||||
|
*/
|
||||||
static malloc_mutex_t ctl_mtx;
|
static malloc_mutex_t ctl_mtx;
|
||||||
static bool ctl_initialized;
|
static bool ctl_initialized;
|
||||||
static uint64_t ctl_epoch;
|
static uint64_t ctl_epoch;
|
||||||
@@ -41,6 +48,13 @@ CTL_PROTO(epoch)
|
|||||||
#ifdef JEMALLOC_TCACHE
|
#ifdef JEMALLOC_TCACHE
|
||||||
CTL_PROTO(tcache_flush)
|
CTL_PROTO(tcache_flush)
|
||||||
#endif
|
#endif
|
||||||
|
CTL_PROTO(thread_arena)
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
CTL_PROTO(thread_allocated)
|
||||||
|
CTL_PROTO(thread_allocatedp)
|
||||||
|
CTL_PROTO(thread_deallocated)
|
||||||
|
CTL_PROTO(thread_deallocatedp)
|
||||||
|
#endif
|
||||||
CTL_PROTO(config_debug)
|
CTL_PROTO(config_debug)
|
||||||
CTL_PROTO(config_dss)
|
CTL_PROTO(config_dss)
|
||||||
CTL_PROTO(config_dynamic_page_shift)
|
CTL_PROTO(config_dynamic_page_shift)
|
||||||
@@ -57,8 +71,15 @@ CTL_PROTO(config_tiny)
|
|||||||
CTL_PROTO(config_tls)
|
CTL_PROTO(config_tls)
|
||||||
CTL_PROTO(config_xmalloc)
|
CTL_PROTO(config_xmalloc)
|
||||||
CTL_PROTO(opt_abort)
|
CTL_PROTO(opt_abort)
|
||||||
|
CTL_PROTO(opt_lg_qspace_max)
|
||||||
|
CTL_PROTO(opt_lg_cspace_max)
|
||||||
|
CTL_PROTO(opt_lg_chunk)
|
||||||
|
CTL_PROTO(opt_narenas)
|
||||||
|
CTL_PROTO(opt_lg_dirty_mult)
|
||||||
|
CTL_PROTO(opt_stats_print)
|
||||||
#ifdef JEMALLOC_FILL
|
#ifdef JEMALLOC_FILL
|
||||||
CTL_PROTO(opt_junk)
|
CTL_PROTO(opt_junk)
|
||||||
|
CTL_PROTO(opt_zero)
|
||||||
#endif
|
#endif
|
||||||
#ifdef JEMALLOC_SYSV
|
#ifdef JEMALLOC_SYSV
|
||||||
CTL_PROTO(opt_sysv)
|
CTL_PROTO(opt_sysv)
|
||||||
@@ -66,27 +87,22 @@ CTL_PROTO(opt_sysv)
|
|||||||
#ifdef JEMALLOC_XMALLOC
|
#ifdef JEMALLOC_XMALLOC
|
||||||
CTL_PROTO(opt_xmalloc)
|
CTL_PROTO(opt_xmalloc)
|
||||||
#endif
|
#endif
|
||||||
#ifdef JEMALLOC_ZERO
|
|
||||||
CTL_PROTO(opt_zero)
|
|
||||||
#endif
|
|
||||||
#ifdef JEMALLOC_TCACHE
|
#ifdef JEMALLOC_TCACHE
|
||||||
CTL_PROTO(opt_tcache)
|
CTL_PROTO(opt_tcache)
|
||||||
CTL_PROTO(opt_lg_tcache_gc_sweep)
|
CTL_PROTO(opt_lg_tcache_gc_sweep)
|
||||||
#endif
|
#endif
|
||||||
#ifdef JEMALLOC_PROF
|
#ifdef JEMALLOC_PROF
|
||||||
CTL_PROTO(opt_prof)
|
CTL_PROTO(opt_prof)
|
||||||
|
CTL_PROTO(opt_prof_prefix)
|
||||||
CTL_PROTO(opt_prof_active)
|
CTL_PROTO(opt_prof_active)
|
||||||
CTL_PROTO(opt_lg_prof_bt_max)
|
CTL_PROTO(opt_lg_prof_bt_max)
|
||||||
CTL_PROTO(opt_lg_prof_sample)
|
CTL_PROTO(opt_lg_prof_sample)
|
||||||
CTL_PROTO(opt_lg_prof_interval)
|
CTL_PROTO(opt_lg_prof_interval)
|
||||||
CTL_PROTO(opt_prof_udump)
|
CTL_PROTO(opt_prof_gdump)
|
||||||
CTL_PROTO(opt_prof_leak)
|
CTL_PROTO(opt_prof_leak)
|
||||||
|
CTL_PROTO(opt_prof_accum)
|
||||||
|
CTL_PROTO(opt_lg_prof_tcmax)
|
||||||
#endif
|
#endif
|
||||||
CTL_PROTO(opt_stats_print)
|
|
||||||
CTL_PROTO(opt_lg_qspace_max)
|
|
||||||
CTL_PROTO(opt_lg_cspace_max)
|
|
||||||
CTL_PROTO(opt_lg_dirty_mult)
|
|
||||||
CTL_PROTO(opt_lg_chunk)
|
|
||||||
#ifdef JEMALLOC_SWAP
|
#ifdef JEMALLOC_SWAP
|
||||||
CTL_PROTO(opt_overcommit)
|
CTL_PROTO(opt_overcommit)
|
||||||
#endif
|
#endif
|
||||||
@@ -125,6 +141,7 @@ CTL_PROTO(arenas_nbins)
|
|||||||
CTL_PROTO(arenas_nhbins)
|
CTL_PROTO(arenas_nhbins)
|
||||||
#endif
|
#endif
|
||||||
CTL_PROTO(arenas_nlruns)
|
CTL_PROTO(arenas_nlruns)
|
||||||
|
CTL_PROTO(arenas_purge)
|
||||||
#ifdef JEMALLOC_PROF
|
#ifdef JEMALLOC_PROF
|
||||||
CTL_PROTO(prof_active)
|
CTL_PROTO(prof_active)
|
||||||
CTL_PROTO(prof_dump)
|
CTL_PROTO(prof_dump)
|
||||||
@@ -165,6 +182,7 @@ CTL_PROTO(stats_arenas_i_lruns_j_highruns)
|
|||||||
CTL_PROTO(stats_arenas_i_lruns_j_curruns)
|
CTL_PROTO(stats_arenas_i_lruns_j_curruns)
|
||||||
INDEX_PROTO(stats_arenas_i_lruns_j)
|
INDEX_PROTO(stats_arenas_i_lruns_j)
|
||||||
#endif
|
#endif
|
||||||
|
CTL_PROTO(stats_arenas_i_nthreads)
|
||||||
CTL_PROTO(stats_arenas_i_pactive)
|
CTL_PROTO(stats_arenas_i_pactive)
|
||||||
CTL_PROTO(stats_arenas_i_pdirty)
|
CTL_PROTO(stats_arenas_i_pdirty)
|
||||||
#ifdef JEMALLOC_STATS
|
#ifdef JEMALLOC_STATS
|
||||||
@@ -175,6 +193,7 @@ CTL_PROTO(stats_arenas_i_purged)
|
|||||||
#endif
|
#endif
|
||||||
INDEX_PROTO(stats_arenas_i)
|
INDEX_PROTO(stats_arenas_i)
|
||||||
#ifdef JEMALLOC_STATS
|
#ifdef JEMALLOC_STATS
|
||||||
|
CTL_PROTO(stats_cactive)
|
||||||
CTL_PROTO(stats_allocated)
|
CTL_PROTO(stats_allocated)
|
||||||
CTL_PROTO(stats_active)
|
CTL_PROTO(stats_active)
|
||||||
CTL_PROTO(stats_mapped)
|
CTL_PROTO(stats_mapped)
|
||||||
@@ -210,6 +229,17 @@ static const ctl_node_t tcache_node[] = {
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static const ctl_node_t thread_node[] = {
|
||||||
|
{NAME("arena"), CTL(thread_arena)}
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
,
|
||||||
|
{NAME("allocated"), CTL(thread_allocated)},
|
||||||
|
{NAME("allocatedp"), CTL(thread_allocatedp)},
|
||||||
|
{NAME("deallocated"), CTL(thread_deallocated)},
|
||||||
|
{NAME("deallocatedp"), CTL(thread_deallocatedp)}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
static const ctl_node_t config_node[] = {
|
static const ctl_node_t config_node[] = {
|
||||||
{NAME("debug"), CTL(config_debug)},
|
{NAME("debug"), CTL(config_debug)},
|
||||||
{NAME("dss"), CTL(config_dss)},
|
{NAME("dss"), CTL(config_dss)},
|
||||||
@@ -230,36 +260,43 @@ static const ctl_node_t config_node[] = {
|
|||||||
|
|
||||||
static const ctl_node_t opt_node[] = {
|
static const ctl_node_t opt_node[] = {
|
||||||
{NAME("abort"), CTL(opt_abort)},
|
{NAME("abort"), CTL(opt_abort)},
|
||||||
|
{NAME("lg_qspace_max"), CTL(opt_lg_qspace_max)},
|
||||||
|
{NAME("lg_cspace_max"), CTL(opt_lg_cspace_max)},
|
||||||
|
{NAME("lg_chunk"), CTL(opt_lg_chunk)},
|
||||||
|
{NAME("narenas"), CTL(opt_narenas)},
|
||||||
|
{NAME("lg_dirty_mult"), CTL(opt_lg_dirty_mult)},
|
||||||
|
{NAME("stats_print"), CTL(opt_stats_print)}
|
||||||
#ifdef JEMALLOC_FILL
|
#ifdef JEMALLOC_FILL
|
||||||
|
,
|
||||||
{NAME("junk"), CTL(opt_junk)},
|
{NAME("junk"), CTL(opt_junk)},
|
||||||
|
{NAME("zero"), CTL(opt_zero)}
|
||||||
#endif
|
#endif
|
||||||
#ifdef JEMALLOC_SYSV
|
#ifdef JEMALLOC_SYSV
|
||||||
{NAME("sysv"), CTL(opt_sysv)},
|
,
|
||||||
|
{NAME("sysv"), CTL(opt_sysv)}
|
||||||
#endif
|
#endif
|
||||||
#ifdef JEMALLOC_XMALLOC
|
#ifdef JEMALLOC_XMALLOC
|
||||||
{NAME("xmalloc"), CTL(opt_xmalloc)},
|
,
|
||||||
#endif
|
{NAME("xmalloc"), CTL(opt_xmalloc)}
|
||||||
#ifdef JEMALLOC_ZERO
|
|
||||||
{NAME("zero"), CTL(opt_zero)},
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef JEMALLOC_TCACHE
|
#ifdef JEMALLOC_TCACHE
|
||||||
|
,
|
||||||
{NAME("tcache"), CTL(opt_tcache)},
|
{NAME("tcache"), CTL(opt_tcache)},
|
||||||
{NAME("lg_tcache_gc_sweep"), CTL(opt_lg_tcache_gc_sweep)},
|
{NAME("lg_tcache_gc_sweep"), CTL(opt_lg_tcache_gc_sweep)}
|
||||||
#endif
|
#endif
|
||||||
#ifdef JEMALLOC_PROF
|
#ifdef JEMALLOC_PROF
|
||||||
|
,
|
||||||
{NAME("prof"), CTL(opt_prof)},
|
{NAME("prof"), CTL(opt_prof)},
|
||||||
|
{NAME("prof_prefix"), CTL(opt_prof_prefix)},
|
||||||
{NAME("prof_active"), CTL(opt_prof_active)},
|
{NAME("prof_active"), CTL(opt_prof_active)},
|
||||||
{NAME("lg_prof_bt_max"), CTL(opt_lg_prof_bt_max)},
|
{NAME("lg_prof_bt_max"), CTL(opt_lg_prof_bt_max)},
|
||||||
{NAME("lg_prof_sample"), CTL(opt_lg_prof_sample)},
|
{NAME("lg_prof_sample"), CTL(opt_lg_prof_sample)},
|
||||||
{NAME("lg_prof_interval"), CTL(opt_lg_prof_interval)},
|
{NAME("lg_prof_interval"), CTL(opt_lg_prof_interval)},
|
||||||
{NAME("prof_udump"), CTL(opt_prof_udump)},
|
{NAME("prof_gdump"), CTL(opt_prof_gdump)},
|
||||||
{NAME("prof_leak"), CTL(opt_prof_leak)},
|
{NAME("prof_leak"), CTL(opt_prof_leak)},
|
||||||
|
{NAME("prof_accum"), CTL(opt_prof_accum)},
|
||||||
|
{NAME("lg_prof_tcmax"), CTL(opt_lg_prof_tcmax)}
|
||||||
#endif
|
#endif
|
||||||
{NAME("stats_print"), CTL(opt_stats_print)},
|
|
||||||
{NAME("lg_qspace_max"), CTL(opt_lg_qspace_max)},
|
|
||||||
{NAME("lg_cspace_max"), CTL(opt_lg_cspace_max)},
|
|
||||||
{NAME("lg_dirty_mult"), CTL(opt_lg_dirty_mult)},
|
|
||||||
{NAME("lg_chunk"), CTL(opt_lg_chunk)}
|
|
||||||
#ifdef JEMALLOC_SWAP
|
#ifdef JEMALLOC_SWAP
|
||||||
,
|
,
|
||||||
{NAME("overcommit"), CTL(opt_overcommit)}
|
{NAME("overcommit"), CTL(opt_overcommit)}
|
||||||
@@ -321,7 +358,8 @@ static const ctl_node_t arenas_node[] = {
|
|||||||
#endif
|
#endif
|
||||||
{NAME("bin"), CHILD(arenas_bin)},
|
{NAME("bin"), CHILD(arenas_bin)},
|
||||||
{NAME("nlruns"), CTL(arenas_nlruns)},
|
{NAME("nlruns"), CTL(arenas_nlruns)},
|
||||||
{NAME("lrun"), CHILD(arenas_lrun)}
|
{NAME("lrun"), CHILD(arenas_lrun)},
|
||||||
|
{NAME("purge"), CTL(arenas_purge)}
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef JEMALLOC_PROF
|
#ifdef JEMALLOC_PROF
|
||||||
@@ -398,6 +436,7 @@ static const ctl_node_t stats_arenas_i_lruns_node[] = {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const ctl_node_t stats_arenas_i_node[] = {
|
static const ctl_node_t stats_arenas_i_node[] = {
|
||||||
|
{NAME("nthreads"), CTL(stats_arenas_i_nthreads)},
|
||||||
{NAME("pactive"), CTL(stats_arenas_i_pactive)},
|
{NAME("pactive"), CTL(stats_arenas_i_pactive)},
|
||||||
{NAME("pdirty"), CTL(stats_arenas_i_pdirty)}
|
{NAME("pdirty"), CTL(stats_arenas_i_pdirty)}
|
||||||
#ifdef JEMALLOC_STATS
|
#ifdef JEMALLOC_STATS
|
||||||
@@ -422,6 +461,7 @@ static const ctl_node_t stats_arenas_node[] = {
|
|||||||
|
|
||||||
static const ctl_node_t stats_node[] = {
|
static const ctl_node_t stats_node[] = {
|
||||||
#ifdef JEMALLOC_STATS
|
#ifdef JEMALLOC_STATS
|
||||||
|
{NAME("cactive"), CTL(stats_cactive)},
|
||||||
{NAME("allocated"), CTL(stats_allocated)},
|
{NAME("allocated"), CTL(stats_allocated)},
|
||||||
{NAME("active"), CTL(stats_active)},
|
{NAME("active"), CTL(stats_active)},
|
||||||
{NAME("mapped"), CTL(stats_mapped)},
|
{NAME("mapped"), CTL(stats_mapped)},
|
||||||
@@ -448,6 +488,7 @@ static const ctl_node_t root_node[] = {
|
|||||||
#ifdef JEMALLOC_TCACHE
|
#ifdef JEMALLOC_TCACHE
|
||||||
{NAME("tcache"), CHILD(tcache)},
|
{NAME("tcache"), CHILD(tcache)},
|
||||||
#endif
|
#endif
|
||||||
|
{NAME("thread"), CHILD(thread)},
|
||||||
{NAME("config"), CHILD(config)},
|
{NAME("config"), CHILD(config)},
|
||||||
{NAME("opt"), CHILD(opt)},
|
{NAME("opt"), CHILD(opt)},
|
||||||
{NAME("arenas"), CHILD(arenas)},
|
{NAME("arenas"), CHILD(arenas)},
|
||||||
@@ -583,6 +624,7 @@ ctl_arena_refresh(arena_t *arena, unsigned i)
|
|||||||
|
|
||||||
ctl_arena_clear(astats);
|
ctl_arena_clear(astats);
|
||||||
|
|
||||||
|
sstats->nthreads += astats->nthreads;
|
||||||
#ifdef JEMALLOC_STATS
|
#ifdef JEMALLOC_STATS
|
||||||
ctl_arena_stats_amerge(astats, arena);
|
ctl_arena_stats_amerge(astats, arena);
|
||||||
/* Merge into sum stats as well. */
|
/* Merge into sum stats as well. */
|
||||||
@@ -620,10 +662,17 @@ ctl_refresh(void)
|
|||||||
* Clear sum stats, since they will be merged into by
|
* Clear sum stats, since they will be merged into by
|
||||||
* ctl_arena_refresh().
|
* ctl_arena_refresh().
|
||||||
*/
|
*/
|
||||||
|
ctl_stats.arenas[narenas].nthreads = 0;
|
||||||
ctl_arena_clear(&ctl_stats.arenas[narenas]);
|
ctl_arena_clear(&ctl_stats.arenas[narenas]);
|
||||||
|
|
||||||
malloc_mutex_lock(&arenas_lock);
|
malloc_mutex_lock(&arenas_lock);
|
||||||
memcpy(tarenas, arenas, sizeof(arena_t *) * narenas);
|
memcpy(tarenas, arenas, sizeof(arena_t *) * narenas);
|
||||||
|
for (i = 0; i < narenas; i++) {
|
||||||
|
if (arenas[i] != NULL)
|
||||||
|
ctl_stats.arenas[i].nthreads = arenas[i]->nthreads;
|
||||||
|
else
|
||||||
|
ctl_stats.arenas[i].nthreads = 0;
|
||||||
|
}
|
||||||
malloc_mutex_unlock(&arenas_lock);
|
malloc_mutex_unlock(&arenas_lock);
|
||||||
for (i = 0; i < narenas; i++) {
|
for (i = 0; i < narenas; i++) {
|
||||||
bool initialized = (tarenas[i] != NULL);
|
bool initialized = (tarenas[i] != NULL);
|
||||||
@@ -654,7 +703,9 @@ ctl_refresh(void)
|
|||||||
static bool
|
static bool
|
||||||
ctl_init(void)
|
ctl_init(void)
|
||||||
{
|
{
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
malloc_mutex_lock(&ctl_mtx);
|
||||||
if (ctl_initialized == false) {
|
if (ctl_initialized == false) {
|
||||||
#ifdef JEMALLOC_STATS
|
#ifdef JEMALLOC_STATS
|
||||||
unsigned i;
|
unsigned i;
|
||||||
@@ -666,8 +717,10 @@ ctl_init(void)
|
|||||||
*/
|
*/
|
||||||
ctl_stats.arenas = (ctl_arena_stats_t *)base_alloc(
|
ctl_stats.arenas = (ctl_arena_stats_t *)base_alloc(
|
||||||
(narenas + 1) * sizeof(ctl_arena_stats_t));
|
(narenas + 1) * sizeof(ctl_arena_stats_t));
|
||||||
if (ctl_stats.arenas == NULL)
|
if (ctl_stats.arenas == NULL) {
|
||||||
return (true);
|
ret = true;
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
memset(ctl_stats.arenas, 0, (narenas + 1) *
|
memset(ctl_stats.arenas, 0, (narenas + 1) *
|
||||||
sizeof(ctl_arena_stats_t));
|
sizeof(ctl_arena_stats_t));
|
||||||
|
|
||||||
@@ -678,8 +731,10 @@ ctl_init(void)
|
|||||||
*/
|
*/
|
||||||
#ifdef JEMALLOC_STATS
|
#ifdef JEMALLOC_STATS
|
||||||
for (i = 0; i <= narenas; i++) {
|
for (i = 0; i <= narenas; i++) {
|
||||||
if (ctl_arena_init(&ctl_stats.arenas[i]))
|
if (ctl_arena_init(&ctl_stats.arenas[i])) {
|
||||||
return (true);
|
ret = true;
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
ctl_stats.arenas[narenas].initialized = true;
|
ctl_stats.arenas[narenas].initialized = true;
|
||||||
@@ -689,7 +744,10 @@ ctl_init(void)
|
|||||||
ctl_initialized = true;
|
ctl_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (false);
|
ret = false;
|
||||||
|
RETURN:
|
||||||
|
malloc_mutex_unlock(&ctl_mtx);
|
||||||
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -799,8 +857,7 @@ ctl_byname(const char *name, void *oldp, size_t *oldlenp, void *newp,
|
|||||||
ctl_node_t const *nodes[CTL_MAX_DEPTH];
|
ctl_node_t const *nodes[CTL_MAX_DEPTH];
|
||||||
size_t mib[CTL_MAX_DEPTH];
|
size_t mib[CTL_MAX_DEPTH];
|
||||||
|
|
||||||
malloc_mutex_lock(&ctl_mtx);
|
if (ctl_initialized == false && ctl_init()) {
|
||||||
if (ctl_init()) {
|
|
||||||
ret = EAGAIN;
|
ret = EAGAIN;
|
||||||
goto RETURN;
|
goto RETURN;
|
||||||
}
|
}
|
||||||
@@ -815,10 +872,9 @@ ctl_byname(const char *name, void *oldp, size_t *oldlenp, void *newp,
|
|||||||
ret = ENOENT;
|
ret = ENOENT;
|
||||||
goto RETURN;
|
goto RETURN;
|
||||||
}
|
}
|
||||||
ret = nodes[depth-1]->ctl(mib, depth, oldp, oldlenp, newp, newlen);
|
|
||||||
|
|
||||||
|
ret = nodes[depth-1]->ctl(mib, depth, oldp, oldlenp, newp, newlen);
|
||||||
RETURN:
|
RETURN:
|
||||||
malloc_mutex_unlock(&ctl_mtx);
|
|
||||||
return(ret);
|
return(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -827,16 +883,13 @@ ctl_nametomib(const char *name, size_t *mibp, size_t *miblenp)
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
malloc_mutex_lock(&ctl_mtx);
|
if (ctl_initialized == false && ctl_init()) {
|
||||||
if (ctl_init()) {
|
|
||||||
ret = EAGAIN;
|
ret = EAGAIN;
|
||||||
goto RETURN;
|
goto RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ctl_lookup(name, NULL, mibp, miblenp);
|
ret = ctl_lookup(name, NULL, mibp, miblenp);
|
||||||
|
|
||||||
RETURN:
|
RETURN:
|
||||||
malloc_mutex_unlock(&ctl_mtx);
|
|
||||||
return(ret);
|
return(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -848,8 +901,7 @@ ctl_bymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
|||||||
const ctl_node_t *node;
|
const ctl_node_t *node;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
malloc_mutex_lock(&ctl_mtx);
|
if (ctl_initialized == false && ctl_init()) {
|
||||||
if (ctl_init()) {
|
|
||||||
ret = EAGAIN;
|
ret = EAGAIN;
|
||||||
goto RETURN;
|
goto RETURN;
|
||||||
}
|
}
|
||||||
@@ -886,7 +938,6 @@ ctl_bymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
|||||||
ret = node->ctl(mib, miblen, oldp, oldlenp, newp, newlen);
|
ret = node->ctl(mib, miblen, oldp, oldlenp, newp, newlen);
|
||||||
|
|
||||||
RETURN:
|
RETURN:
|
||||||
malloc_mutex_unlock(&ctl_mtx);
|
|
||||||
return(ret);
|
return(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -949,6 +1000,29 @@ ctl_boot(void)
|
|||||||
|
|
||||||
#define CTL_RO_GEN(n, v, t) \
|
#define CTL_RO_GEN(n, v, t) \
|
||||||
static int \
|
static int \
|
||||||
|
n##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, \
|
||||||
|
void *newp, size_t newlen) \
|
||||||
|
{ \
|
||||||
|
int ret; \
|
||||||
|
t oldval; \
|
||||||
|
\
|
||||||
|
malloc_mutex_lock(&ctl_mtx); \
|
||||||
|
READONLY(); \
|
||||||
|
oldval = v; \
|
||||||
|
READ(oldval, t); \
|
||||||
|
\
|
||||||
|
ret = 0; \
|
||||||
|
RETURN: \
|
||||||
|
malloc_mutex_unlock(&ctl_mtx); \
|
||||||
|
return (ret); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ctl_mtx is not acquired, under the assumption that no pertinent data will
|
||||||
|
* mutate during the call.
|
||||||
|
*/
|
||||||
|
#define CTL_RO_NL_GEN(n, v, t) \
|
||||||
|
static int \
|
||||||
n##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, \
|
n##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, \
|
||||||
void *newp, size_t newlen) \
|
void *newp, size_t newlen) \
|
||||||
{ \
|
{ \
|
||||||
@@ -998,7 +1072,7 @@ RETURN: \
|
|||||||
return (ret); \
|
return (ret); \
|
||||||
}
|
}
|
||||||
|
|
||||||
CTL_RO_GEN(version, JEMALLOC_VERSION, const char *)
|
CTL_RO_NL_GEN(version, JEMALLOC_VERSION, const char *)
|
||||||
|
|
||||||
static int
|
static int
|
||||||
epoch_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
epoch_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
||||||
@@ -1007,6 +1081,7 @@ epoch_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
|||||||
int ret;
|
int ret;
|
||||||
uint64_t newval;
|
uint64_t newval;
|
||||||
|
|
||||||
|
malloc_mutex_lock(&ctl_mtx);
|
||||||
newval = 0;
|
newval = 0;
|
||||||
WRITE(newval, uint64_t);
|
WRITE(newval, uint64_t);
|
||||||
if (newval != 0)
|
if (newval != 0)
|
||||||
@@ -1015,6 +1090,7 @@ epoch_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
|||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
RETURN:
|
RETURN:
|
||||||
|
malloc_mutex_unlock(&ctl_mtx);
|
||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1028,13 +1104,13 @@ tcache_flush_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
|||||||
|
|
||||||
VOID();
|
VOID();
|
||||||
|
|
||||||
tcache = tcache_tls;
|
tcache = TCACHE_GET();
|
||||||
if (tcache == NULL) {
|
if (tcache == NULL) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
goto RETURN;
|
goto RETURN;
|
||||||
}
|
}
|
||||||
tcache_destroy(tcache);
|
tcache_destroy(tcache);
|
||||||
tcache_tls = NULL;
|
TCACHE_SET(NULL);
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
RETURN:
|
RETURN:
|
||||||
@@ -1042,6 +1118,60 @@ RETURN:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int
|
||||||
|
thread_arena_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
||||||
|
void *newp, size_t newlen)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
unsigned newind, oldind;
|
||||||
|
|
||||||
|
newind = oldind = choose_arena()->ind;
|
||||||
|
WRITE(newind, unsigned);
|
||||||
|
READ(oldind, unsigned);
|
||||||
|
if (newind != oldind) {
|
||||||
|
arena_t *arena;
|
||||||
|
|
||||||
|
if (newind >= narenas) {
|
||||||
|
/* New arena index is out of range. */
|
||||||
|
ret = EFAULT;
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize arena if necessary. */
|
||||||
|
malloc_mutex_lock(&arenas_lock);
|
||||||
|
if ((arena = arenas[newind]) == NULL)
|
||||||
|
arena = arenas_extend(newind);
|
||||||
|
arenas[oldind]->nthreads--;
|
||||||
|
arenas[newind]->nthreads++;
|
||||||
|
malloc_mutex_unlock(&arenas_lock);
|
||||||
|
if (arena == NULL) {
|
||||||
|
ret = EAGAIN;
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set new arena association. */
|
||||||
|
ARENA_SET(arena);
|
||||||
|
#ifdef JEMALLOC_TCACHE
|
||||||
|
{
|
||||||
|
tcache_t *tcache = TCACHE_GET();
|
||||||
|
if (tcache != NULL)
|
||||||
|
tcache->arena = arena;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
RETURN:
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
CTL_RO_NL_GEN(thread_allocated, ALLOCATED_GET(), uint64_t);
|
||||||
|
CTL_RO_NL_GEN(thread_allocatedp, ALLOCATEDP_GET(), uint64_t *);
|
||||||
|
CTL_RO_NL_GEN(thread_deallocated, DEALLOCATED_GET(), uint64_t);
|
||||||
|
CTL_RO_NL_GEN(thread_deallocatedp, DEALLOCATEDP_GET(), uint64_t *);
|
||||||
|
#endif
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
#ifdef JEMALLOC_DEBUG
|
#ifdef JEMALLOC_DEBUG
|
||||||
@@ -1136,46 +1266,48 @@ CTL_RO_FALSE_GEN(config_xmalloc)
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
CTL_RO_GEN(opt_abort, opt_abort, bool)
|
CTL_RO_NL_GEN(opt_abort, opt_abort, bool)
|
||||||
|
CTL_RO_NL_GEN(opt_lg_qspace_max, opt_lg_qspace_max, size_t)
|
||||||
|
CTL_RO_NL_GEN(opt_lg_cspace_max, opt_lg_cspace_max, size_t)
|
||||||
|
CTL_RO_NL_GEN(opt_lg_chunk, opt_lg_chunk, size_t)
|
||||||
|
CTL_RO_NL_GEN(opt_narenas, opt_narenas, size_t)
|
||||||
|
CTL_RO_NL_GEN(opt_lg_dirty_mult, opt_lg_dirty_mult, ssize_t)
|
||||||
|
CTL_RO_NL_GEN(opt_stats_print, opt_stats_print, bool)
|
||||||
#ifdef JEMALLOC_FILL
|
#ifdef JEMALLOC_FILL
|
||||||
CTL_RO_GEN(opt_junk, opt_junk, bool)
|
CTL_RO_NL_GEN(opt_junk, opt_junk, bool)
|
||||||
|
CTL_RO_NL_GEN(opt_zero, opt_zero, bool)
|
||||||
#endif
|
#endif
|
||||||
#ifdef JEMALLOC_SYSV
|
#ifdef JEMALLOC_SYSV
|
||||||
CTL_RO_GEN(opt_sysv, opt_sysv, bool)
|
CTL_RO_NL_GEN(opt_sysv, opt_sysv, bool)
|
||||||
#endif
|
#endif
|
||||||
#ifdef JEMALLOC_XMALLOC
|
#ifdef JEMALLOC_XMALLOC
|
||||||
CTL_RO_GEN(opt_xmalloc, opt_xmalloc, bool)
|
CTL_RO_NL_GEN(opt_xmalloc, opt_xmalloc, bool)
|
||||||
#endif
|
|
||||||
#ifdef JEMALLOC_ZERO
|
|
||||||
CTL_RO_GEN(opt_zero, opt_zero, bool)
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef JEMALLOC_TCACHE
|
#ifdef JEMALLOC_TCACHE
|
||||||
CTL_RO_GEN(opt_tcache, opt_tcache, bool)
|
CTL_RO_NL_GEN(opt_tcache, opt_tcache, bool)
|
||||||
CTL_RO_GEN(opt_lg_tcache_gc_sweep, opt_lg_tcache_gc_sweep, ssize_t)
|
CTL_RO_NL_GEN(opt_lg_tcache_gc_sweep, opt_lg_tcache_gc_sweep, ssize_t)
|
||||||
#endif
|
#endif
|
||||||
#ifdef JEMALLOC_PROF
|
#ifdef JEMALLOC_PROF
|
||||||
CTL_RO_GEN(opt_prof, opt_prof, bool)
|
CTL_RO_NL_GEN(opt_prof, opt_prof, bool)
|
||||||
CTL_RO_GEN(opt_prof_active, opt_prof_active, bool)
|
CTL_RO_NL_GEN(opt_prof_prefix, opt_prof_prefix, const char *)
|
||||||
CTL_RO_GEN(opt_lg_prof_bt_max, opt_lg_prof_bt_max, size_t)
|
CTL_RO_GEN(opt_prof_active, opt_prof_active, bool) /* Mutable. */
|
||||||
CTL_RO_GEN(opt_lg_prof_sample, opt_lg_prof_sample, size_t)
|
CTL_RO_NL_GEN(opt_lg_prof_bt_max, opt_lg_prof_bt_max, size_t)
|
||||||
CTL_RO_GEN(opt_lg_prof_interval, opt_lg_prof_interval, ssize_t)
|
CTL_RO_NL_GEN(opt_lg_prof_sample, opt_lg_prof_sample, size_t)
|
||||||
CTL_RO_GEN(opt_prof_udump, opt_prof_udump, bool)
|
CTL_RO_NL_GEN(opt_lg_prof_interval, opt_lg_prof_interval, ssize_t)
|
||||||
CTL_RO_GEN(opt_prof_leak, opt_prof_leak, bool)
|
CTL_RO_NL_GEN(opt_prof_gdump, opt_prof_gdump, bool)
|
||||||
|
CTL_RO_NL_GEN(opt_prof_leak, opt_prof_leak, bool)
|
||||||
|
CTL_RO_NL_GEN(opt_prof_accum, opt_prof_accum, bool)
|
||||||
|
CTL_RO_NL_GEN(opt_lg_prof_tcmax, opt_lg_prof_tcmax, ssize_t)
|
||||||
#endif
|
#endif
|
||||||
CTL_RO_GEN(opt_stats_print, opt_stats_print, bool)
|
|
||||||
CTL_RO_GEN(opt_lg_qspace_max, opt_lg_qspace_max, size_t)
|
|
||||||
CTL_RO_GEN(opt_lg_cspace_max, opt_lg_cspace_max, size_t)
|
|
||||||
CTL_RO_GEN(opt_lg_dirty_mult, opt_lg_dirty_mult, ssize_t)
|
|
||||||
CTL_RO_GEN(opt_lg_chunk, opt_lg_chunk, size_t)
|
|
||||||
#ifdef JEMALLOC_SWAP
|
#ifdef JEMALLOC_SWAP
|
||||||
CTL_RO_GEN(opt_overcommit, opt_overcommit, bool)
|
CTL_RO_NL_GEN(opt_overcommit, opt_overcommit, bool)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
CTL_RO_GEN(arenas_bin_i_size, arenas[0]->bins[mib[2]].reg_size, size_t)
|
CTL_RO_NL_GEN(arenas_bin_i_size, arena_bin_info[mib[2]].reg_size, size_t)
|
||||||
CTL_RO_GEN(arenas_bin_i_nregs, arenas[0]->bins[mib[2]].nregs, uint32_t)
|
CTL_RO_NL_GEN(arenas_bin_i_nregs, arena_bin_info[mib[2]].nregs, uint32_t)
|
||||||
CTL_RO_GEN(arenas_bin_i_run_size, arenas[0]->bins[mib[2]].run_size, size_t)
|
CTL_RO_NL_GEN(arenas_bin_i_run_size, arena_bin_info[mib[2]].run_size, size_t)
|
||||||
const ctl_node_t *
|
const ctl_node_t *
|
||||||
arenas_bin_i_index(const size_t *mib, size_t miblen, size_t i)
|
arenas_bin_i_index(const size_t *mib, size_t miblen, size_t i)
|
||||||
{
|
{
|
||||||
@@ -1185,7 +1317,7 @@ arenas_bin_i_index(const size_t *mib, size_t miblen, size_t i)
|
|||||||
return (super_arenas_bin_i_node);
|
return (super_arenas_bin_i_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
CTL_RO_GEN(arenas_lrun_i_size, ((mib[2]+1) << PAGE_SHIFT), size_t)
|
CTL_RO_NL_GEN(arenas_lrun_i_size, ((mib[2]+1) << PAGE_SHIFT), size_t)
|
||||||
const ctl_node_t *
|
const ctl_node_t *
|
||||||
arenas_lrun_i_index(const size_t *mib, size_t miblen, size_t i)
|
arenas_lrun_i_index(const size_t *mib, size_t miblen, size_t i)
|
||||||
{
|
{
|
||||||
@@ -1195,7 +1327,7 @@ arenas_lrun_i_index(const size_t *mib, size_t miblen, size_t i)
|
|||||||
return (super_arenas_lrun_i_node);
|
return (super_arenas_lrun_i_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
CTL_RO_GEN(arenas_narenas, narenas, unsigned)
|
CTL_RO_NL_GEN(arenas_narenas, narenas, unsigned)
|
||||||
|
|
||||||
static int
|
static int
|
||||||
arenas_initialized_ctl(const size_t *mib, size_t miblen, void *oldp,
|
arenas_initialized_ctl(const size_t *mib, size_t miblen, void *oldp,
|
||||||
@@ -1204,6 +1336,7 @@ arenas_initialized_ctl(const size_t *mib, size_t miblen, void *oldp,
|
|||||||
int ret;
|
int ret;
|
||||||
unsigned nread, i;
|
unsigned nread, i;
|
||||||
|
|
||||||
|
malloc_mutex_lock(&ctl_mtx);
|
||||||
READONLY();
|
READONLY();
|
||||||
if (*oldlenp != narenas * sizeof(bool)) {
|
if (*oldlenp != narenas * sizeof(bool)) {
|
||||||
ret = EINVAL;
|
ret = EINVAL;
|
||||||
@@ -1218,36 +1351,75 @@ arenas_initialized_ctl(const size_t *mib, size_t miblen, void *oldp,
|
|||||||
((bool *)oldp)[i] = ctl_stats.arenas[i].initialized;
|
((bool *)oldp)[i] = ctl_stats.arenas[i].initialized;
|
||||||
|
|
||||||
RETURN:
|
RETURN:
|
||||||
|
malloc_mutex_unlock(&ctl_mtx);
|
||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
CTL_RO_GEN(arenas_quantum, QUANTUM, size_t)
|
CTL_RO_NL_GEN(arenas_quantum, QUANTUM, size_t)
|
||||||
CTL_RO_GEN(arenas_cacheline, CACHELINE, size_t)
|
CTL_RO_NL_GEN(arenas_cacheline, CACHELINE, size_t)
|
||||||
CTL_RO_GEN(arenas_subpage, SUBPAGE, size_t)
|
CTL_RO_NL_GEN(arenas_subpage, SUBPAGE, size_t)
|
||||||
CTL_RO_GEN(arenas_pagesize, PAGE_SIZE, size_t)
|
CTL_RO_NL_GEN(arenas_pagesize, PAGE_SIZE, size_t)
|
||||||
CTL_RO_GEN(arenas_chunksize, chunksize, size_t)
|
CTL_RO_NL_GEN(arenas_chunksize, chunksize, size_t)
|
||||||
#ifdef JEMALLOC_TINY
|
#ifdef JEMALLOC_TINY
|
||||||
CTL_RO_GEN(arenas_tspace_min, (1U << LG_TINY_MIN), size_t)
|
CTL_RO_NL_GEN(arenas_tspace_min, (1U << LG_TINY_MIN), size_t)
|
||||||
CTL_RO_GEN(arenas_tspace_max, (qspace_min >> 1), size_t)
|
CTL_RO_NL_GEN(arenas_tspace_max, (qspace_min >> 1), size_t)
|
||||||
#endif
|
#endif
|
||||||
CTL_RO_GEN(arenas_qspace_min, qspace_min, size_t)
|
CTL_RO_NL_GEN(arenas_qspace_min, qspace_min, size_t)
|
||||||
CTL_RO_GEN(arenas_qspace_max, qspace_max, size_t)
|
CTL_RO_NL_GEN(arenas_qspace_max, qspace_max, size_t)
|
||||||
CTL_RO_GEN(arenas_cspace_min, cspace_min, size_t)
|
CTL_RO_NL_GEN(arenas_cspace_min, cspace_min, size_t)
|
||||||
CTL_RO_GEN(arenas_cspace_max, cspace_max, size_t)
|
CTL_RO_NL_GEN(arenas_cspace_max, cspace_max, size_t)
|
||||||
CTL_RO_GEN(arenas_sspace_min, sspace_min, size_t)
|
CTL_RO_NL_GEN(arenas_sspace_min, sspace_min, size_t)
|
||||||
CTL_RO_GEN(arenas_sspace_max, sspace_max, size_t)
|
CTL_RO_NL_GEN(arenas_sspace_max, sspace_max, size_t)
|
||||||
#ifdef JEMALLOC_TCACHE
|
#ifdef JEMALLOC_TCACHE
|
||||||
CTL_RO_GEN(arenas_tcache_max, tcache_maxclass, size_t)
|
CTL_RO_NL_GEN(arenas_tcache_max, tcache_maxclass, size_t)
|
||||||
#endif
|
#endif
|
||||||
CTL_RO_GEN(arenas_ntbins, ntbins, unsigned)
|
CTL_RO_NL_GEN(arenas_ntbins, ntbins, unsigned)
|
||||||
CTL_RO_GEN(arenas_nqbins, nqbins, unsigned)
|
CTL_RO_NL_GEN(arenas_nqbins, nqbins, unsigned)
|
||||||
CTL_RO_GEN(arenas_ncbins, ncbins, unsigned)
|
CTL_RO_NL_GEN(arenas_ncbins, ncbins, unsigned)
|
||||||
CTL_RO_GEN(arenas_nsbins, nsbins, unsigned)
|
CTL_RO_NL_GEN(arenas_nsbins, nsbins, unsigned)
|
||||||
CTL_RO_GEN(arenas_nbins, nbins, unsigned)
|
CTL_RO_NL_GEN(arenas_nbins, nbins, unsigned)
|
||||||
#ifdef JEMALLOC_TCACHE
|
#ifdef JEMALLOC_TCACHE
|
||||||
CTL_RO_GEN(arenas_nhbins, nhbins, unsigned)
|
CTL_RO_NL_GEN(arenas_nhbins, nhbins, unsigned)
|
||||||
#endif
|
#endif
|
||||||
CTL_RO_GEN(arenas_nlruns, nlclasses, size_t)
|
CTL_RO_NL_GEN(arenas_nlruns, nlclasses, size_t)
|
||||||
|
|
||||||
|
static int
|
||||||
|
arenas_purge_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
||||||
|
void *newp, size_t newlen)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
unsigned arena;
|
||||||
|
|
||||||
|
WRITEONLY();
|
||||||
|
arena = UINT_MAX;
|
||||||
|
WRITE(arena, unsigned);
|
||||||
|
if (newp != NULL && arena >= narenas) {
|
||||||
|
ret = EFAULT;
|
||||||
|
goto RETURN;
|
||||||
|
} else {
|
||||||
|
arena_t *tarenas[narenas];
|
||||||
|
|
||||||
|
malloc_mutex_lock(&arenas_lock);
|
||||||
|
memcpy(tarenas, arenas, sizeof(arena_t *) * narenas);
|
||||||
|
malloc_mutex_unlock(&arenas_lock);
|
||||||
|
|
||||||
|
if (arena == UINT_MAX) {
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < narenas; i++) {
|
||||||
|
if (tarenas[i] != NULL)
|
||||||
|
arena_purge_all(tarenas[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert(arena < narenas);
|
||||||
|
if (tarenas[arena] != NULL)
|
||||||
|
arena_purge_all(tarenas[arena]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
RETURN:
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
@@ -1259,6 +1431,7 @@ prof_active_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
|||||||
int ret;
|
int ret;
|
||||||
bool oldval;
|
bool oldval;
|
||||||
|
|
||||||
|
malloc_mutex_lock(&ctl_mtx); /* Protect opt_prof_active. */
|
||||||
oldval = opt_prof_active;
|
oldval = opt_prof_active;
|
||||||
if (newp != NULL) {
|
if (newp != NULL) {
|
||||||
/*
|
/*
|
||||||
@@ -1273,6 +1446,7 @@ prof_active_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
|||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
RETURN:
|
RETURN:
|
||||||
|
malloc_mutex_unlock(&ctl_mtx);
|
||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1296,7 +1470,7 @@ RETURN:
|
|||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
CTL_RO_GEN(prof_interval, prof_interval, uint64_t)
|
CTL_RO_NL_GEN(prof_interval, prof_interval, uint64_t)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@@ -1378,6 +1552,7 @@ stats_arenas_i_lruns_j_index(const size_t *mib, size_t miblen, size_t j)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
CTL_RO_GEN(stats_arenas_i_nthreads, ctl_stats.arenas[mib[2]].nthreads, unsigned)
|
||||||
CTL_RO_GEN(stats_arenas_i_pactive, ctl_stats.arenas[mib[2]].pactive, size_t)
|
CTL_RO_GEN(stats_arenas_i_pactive, ctl_stats.arenas[mib[2]].pactive, size_t)
|
||||||
CTL_RO_GEN(stats_arenas_i_pdirty, ctl_stats.arenas[mib[2]].pdirty, size_t)
|
CTL_RO_GEN(stats_arenas_i_pdirty, ctl_stats.arenas[mib[2]].pdirty, size_t)
|
||||||
#ifdef JEMALLOC_STATS
|
#ifdef JEMALLOC_STATS
|
||||||
@@ -1394,13 +1569,22 @@ CTL_RO_GEN(stats_arenas_i_purged, ctl_stats.arenas[mib[2]].astats.purged,
|
|||||||
const ctl_node_t *
|
const ctl_node_t *
|
||||||
stats_arenas_i_index(const size_t *mib, size_t miblen, size_t i)
|
stats_arenas_i_index(const size_t *mib, size_t miblen, size_t i)
|
||||||
{
|
{
|
||||||
|
const ctl_node_t * ret;
|
||||||
|
|
||||||
if (ctl_stats.arenas[i].initialized == false)
|
malloc_mutex_lock(&ctl_mtx);
|
||||||
return (NULL);
|
if (ctl_stats.arenas[i].initialized == false) {
|
||||||
return (super_stats_arenas_i_node);
|
ret = NULL;
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = super_stats_arenas_i_node;
|
||||||
|
RETURN:
|
||||||
|
malloc_mutex_unlock(&ctl_mtx);
|
||||||
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JEMALLOC_STATS
|
#ifdef JEMALLOC_STATS
|
||||||
|
CTL_RO_GEN(stats_cactive, &stats_cactive, size_t *)
|
||||||
CTL_RO_GEN(stats_allocated, ctl_stats.allocated, size_t)
|
CTL_RO_GEN(stats_allocated, ctl_stats.allocated, size_t)
|
||||||
CTL_RO_GEN(stats_active, ctl_stats.active, size_t)
|
CTL_RO_GEN(stats_active, ctl_stats.active, size_t)
|
||||||
CTL_RO_GEN(stats_mapped, ctl_stats.mapped, size_t)
|
CTL_RO_GEN(stats_mapped, ctl_stats.mapped, size_t)
|
||||||
@@ -1419,6 +1603,7 @@ swap_prezeroed_ctl(const size_t *mib, size_t miblen, void *oldp,
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
malloc_mutex_lock(&ctl_mtx);
|
||||||
if (swap_enabled) {
|
if (swap_enabled) {
|
||||||
READONLY();
|
READONLY();
|
||||||
} else {
|
} else {
|
||||||
@@ -1436,6 +1621,7 @@ swap_prezeroed_ctl(const size_t *mib, size_t miblen, void *oldp,
|
|||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
RETURN:
|
RETURN:
|
||||||
|
malloc_mutex_unlock(&ctl_mtx);
|
||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1447,6 +1633,7 @@ swap_fds_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
malloc_mutex_lock(&ctl_mtx);
|
||||||
if (swap_enabled) {
|
if (swap_enabled) {
|
||||||
READONLY();
|
READONLY();
|
||||||
} else if (newp != NULL) {
|
} else if (newp != NULL) {
|
||||||
@@ -1477,6 +1664,7 @@ swap_fds_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
|||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
RETURN:
|
RETURN:
|
||||||
|
malloc_mutex_unlock(&ctl_mtx);
|
||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
1881
src/jemalloc.c
Normal file
1881
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"
|
||||||
@@ -55,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);
|
||||||
|
}
|
||||||
@@ -39,6 +39,10 @@
|
|||||||
|
|
||||||
bool opt_stats_print = false;
|
bool opt_stats_print = false;
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_STATS
|
||||||
|
size_t stats_cactive = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* Function prototypes for non-inline static functions. */
|
/* Function prototypes for non-inline static functions. */
|
||||||
|
|
||||||
@@ -57,12 +61,12 @@ static void stats_arena_print(void (*write_cb)(void *, const char *),
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* We don't want to depend on vsnprintf() for production builds, since that can
|
* We don't want to depend on vsnprintf() for production builds, since that can
|
||||||
* cause unnecessary bloat for static binaries. umax2s() provides minimal
|
* cause unnecessary bloat for static binaries. u2s() provides minimal integer
|
||||||
* integer printing functionality, so that malloc_printf() use can be limited to
|
* printing functionality, so that malloc_printf() use can be limited to
|
||||||
* JEMALLOC_STATS code.
|
* JEMALLOC_STATS code.
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
umax2s(uintmax_t x, unsigned base, char *s)
|
u2s(uint64_t x, unsigned base, char *s)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
@@ -72,8 +76,8 @@ umax2s(uintmax_t x, unsigned base, char *s)
|
|||||||
case 10:
|
case 10:
|
||||||
do {
|
do {
|
||||||
i--;
|
i--;
|
||||||
s[i] = "0123456789"[x % 10];
|
s[i] = "0123456789"[x % (uint64_t)10];
|
||||||
x /= 10;
|
x /= (uint64_t)10;
|
||||||
} while (x > 0);
|
} while (x > 0);
|
||||||
break;
|
break;
|
||||||
case 16:
|
case 16:
|
||||||
@@ -86,8 +90,9 @@ umax2s(uintmax_t x, unsigned base, char *s)
|
|||||||
default:
|
default:
|
||||||
do {
|
do {
|
||||||
i--;
|
i--;
|
||||||
s[i] = "0123456789abcdefghijklmnopqrstuvwxyz"[x % base];
|
s[i] = "0123456789abcdefghijklmnopqrstuvwxyz"[x %
|
||||||
x /= base;
|
(uint64_t)base];
|
||||||
|
x /= (uint64_t)base;
|
||||||
} while (x > 0);
|
} while (x > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,6 +323,7 @@ static void
|
|||||||
stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque,
|
stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque,
|
||||||
unsigned i)
|
unsigned i)
|
||||||
{
|
{
|
||||||
|
unsigned nthreads;
|
||||||
size_t pagesize, pactive, pdirty, mapped;
|
size_t pagesize, pactive, pdirty, mapped;
|
||||||
uint64_t npurge, nmadvise, purged;
|
uint64_t npurge, nmadvise, purged;
|
||||||
size_t small_allocated;
|
size_t small_allocated;
|
||||||
@@ -327,6 +333,9 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque,
|
|||||||
|
|
||||||
CTL_GET("arenas.pagesize", &pagesize, size_t);
|
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.pactive", &pactive, size_t);
|
||||||
CTL_I_GET("stats.arenas.0.pdirty", &pdirty, 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.npurge", &npurge, uint64_t);
|
||||||
@@ -374,6 +383,7 @@ void
|
|||||||
stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
|
stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
|
||||||
const char *opts)
|
const char *opts)
|
||||||
{
|
{
|
||||||
|
int err;
|
||||||
uint64_t epoch;
|
uint64_t epoch;
|
||||||
size_t u64sz;
|
size_t u64sz;
|
||||||
char s[UMAX2S_BUFSIZE];
|
char s[UMAX2S_BUFSIZE];
|
||||||
@@ -383,10 +393,27 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
|
|||||||
bool bins = true;
|
bool bins = true;
|
||||||
bool large = true;
|
bool large = true;
|
||||||
|
|
||||||
/* Refresh stats, in case mallctl() was called by the application. */
|
/*
|
||||||
|
* 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;
|
epoch = 1;
|
||||||
u64sz = sizeof(uint64_t);
|
u64sz = sizeof(uint64_t);
|
||||||
xmallctl("epoch", &epoch, &u64sz, &epoch, 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) {
|
if (write_cb == NULL) {
|
||||||
/*
|
/*
|
||||||
@@ -430,10 +457,12 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
|
|||||||
bool bv;
|
bool bv;
|
||||||
unsigned uv;
|
unsigned uv;
|
||||||
ssize_t ssv;
|
ssize_t ssv;
|
||||||
size_t sv, bsz, ssz;
|
size_t sv, bsz, ssz, sssz, cpsz;
|
||||||
|
|
||||||
bsz = sizeof(bool);
|
bsz = sizeof(bool);
|
||||||
ssz = sizeof(size_t);
|
ssz = sizeof(size_t);
|
||||||
|
sssz = sizeof(ssize_t);
|
||||||
|
cpsz = sizeof(const char *);
|
||||||
|
|
||||||
CTL_GET("version", &cpv, const char *);
|
CTL_GET("version", &cpv, const char *);
|
||||||
write_cb(cbopaque, "Version: ");
|
write_cb(cbopaque, "Version: ");
|
||||||
@@ -444,113 +473,140 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
|
|||||||
write_cb(cbopaque, bv ? "enabled" : "disabled");
|
write_cb(cbopaque, bv ? "enabled" : "disabled");
|
||||||
write_cb(cbopaque, "\n");
|
write_cb(cbopaque, "\n");
|
||||||
|
|
||||||
write_cb(cbopaque, "Boolean JEMALLOC_OPTIONS: ");
|
#define OPT_WRITE_BOOL(n) \
|
||||||
if ((err = JEMALLOC_P(mallctl)("opt.abort", &bv, &bsz, NULL, 0))
|
if ((err = JEMALLOC_P(mallctl)("opt."#n, &bv, &bsz, \
|
||||||
== 0)
|
NULL, 0)) == 0) { \
|
||||||
write_cb(cbopaque, bv ? "A" : "a");
|
write_cb(cbopaque, " opt."#n": "); \
|
||||||
if ((err = JEMALLOC_P(mallctl)("prof.active", &bv, &bsz,
|
write_cb(cbopaque, bv ? "true" : "false"); \
|
||||||
NULL, 0)) == 0)
|
write_cb(cbopaque, "\n"); \
|
||||||
write_cb(cbopaque, bv ? "E" : "e");
|
}
|
||||||
if ((err = JEMALLOC_P(mallctl)("opt.prof", &bv, &bsz, NULL, 0))
|
#define OPT_WRITE_SIZE_T(n) \
|
||||||
== 0)
|
if ((err = JEMALLOC_P(mallctl)("opt."#n, &sv, &ssz, \
|
||||||
write_cb(cbopaque, bv ? "F" : "f");
|
NULL, 0)) == 0) { \
|
||||||
if ((err = JEMALLOC_P(mallctl)("opt.tcache", &bv, &bsz, NULL,
|
write_cb(cbopaque, " opt."#n": "); \
|
||||||
0)) == 0)
|
write_cb(cbopaque, u2s(sv, 10, s)); \
|
||||||
write_cb(cbopaque, bv ? "H" : "h");
|
write_cb(cbopaque, "\n"); \
|
||||||
if ((err = JEMALLOC_P(mallctl)("opt.junk", &bv, &bsz, NULL, 0))
|
}
|
||||||
== 0)
|
#define OPT_WRITE_SSIZE_T(n) \
|
||||||
write_cb(cbopaque, bv ? "J" : "j");
|
if ((err = JEMALLOC_P(mallctl)("opt."#n, &ssv, &sssz, \
|
||||||
if ((err = JEMALLOC_P(mallctl)("opt.prof_leak", &bv, &bsz, NULL,
|
NULL, 0)) == 0) { \
|
||||||
0)) == 0)
|
if (ssv >= 0) { \
|
||||||
write_cb(cbopaque, bv ? "L" : "l");
|
write_cb(cbopaque, " opt."#n": "); \
|
||||||
if ((err = JEMALLOC_P(mallctl)("opt.overcommit", &bv, &bsz,
|
write_cb(cbopaque, u2s(ssv, 10, s)); \
|
||||||
NULL, 0)) == 0)
|
} else { \
|
||||||
write_cb(cbopaque, bv ? "O" : "o");
|
write_cb(cbopaque, " opt."#n": -"); \
|
||||||
if ((err = JEMALLOC_P(mallctl)("opt.stats_print", &bv, &bsz,
|
write_cb(cbopaque, u2s(-ssv, 10, s)); \
|
||||||
NULL, 0)) == 0)
|
} \
|
||||||
write_cb(cbopaque, bv ? "P" : "p");
|
write_cb(cbopaque, "\n"); \
|
||||||
if ((err = JEMALLOC_P(mallctl)("opt.prof_udump", &bv, &bsz,
|
}
|
||||||
NULL, 0)) == 0)
|
#define OPT_WRITE_CHAR_P(n) \
|
||||||
write_cb(cbopaque, bv ? "U" : "u");
|
if ((err = JEMALLOC_P(mallctl)("opt."#n, &cpv, &cpsz, \
|
||||||
if ((err = JEMALLOC_P(mallctl)("opt.sysv", &bv, &bsz, NULL, 0))
|
NULL, 0)) == 0) { \
|
||||||
== 0)
|
write_cb(cbopaque, " opt."#n": \""); \
|
||||||
write_cb(cbopaque, bv ? "V" : "v");
|
write_cb(cbopaque, cpv); \
|
||||||
if ((err = JEMALLOC_P(mallctl)("opt.xmalloc", &bv, &bsz, NULL,
|
write_cb(cbopaque, "\"\n"); \
|
||||||
0)) == 0)
|
}
|
||||||
write_cb(cbopaque, bv ? "X" : "x");
|
|
||||||
if ((err = JEMALLOC_P(mallctl)("opt.zero", &bv, &bsz, NULL, 0))
|
write_cb(cbopaque, "Run-time option settings:\n");
|
||||||
== 0)
|
OPT_WRITE_BOOL(abort)
|
||||||
write_cb(cbopaque, bv ? "Z" : "z");
|
OPT_WRITE_SIZE_T(lg_qspace_max)
|
||||||
write_cb(cbopaque, "\n");
|
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, "CPUs: ");
|
||||||
write_cb(cbopaque, umax2s(ncpus, 10, s));
|
write_cb(cbopaque, u2s(ncpus, 10, s));
|
||||||
write_cb(cbopaque, "\n");
|
write_cb(cbopaque, "\n");
|
||||||
|
|
||||||
CTL_GET("arenas.narenas", &uv, unsigned);
|
CTL_GET("arenas.narenas", &uv, unsigned);
|
||||||
write_cb(cbopaque, "Max arenas: ");
|
write_cb(cbopaque, "Max arenas: ");
|
||||||
write_cb(cbopaque, umax2s(uv, 10, s));
|
write_cb(cbopaque, u2s(uv, 10, s));
|
||||||
write_cb(cbopaque, "\n");
|
write_cb(cbopaque, "\n");
|
||||||
|
|
||||||
write_cb(cbopaque, "Pointer size: ");
|
write_cb(cbopaque, "Pointer size: ");
|
||||||
write_cb(cbopaque, umax2s(sizeof(void *), 10, s));
|
write_cb(cbopaque, u2s(sizeof(void *), 10, s));
|
||||||
write_cb(cbopaque, "\n");
|
write_cb(cbopaque, "\n");
|
||||||
|
|
||||||
CTL_GET("arenas.quantum", &sv, size_t);
|
CTL_GET("arenas.quantum", &sv, size_t);
|
||||||
write_cb(cbopaque, "Quantum size: ");
|
write_cb(cbopaque, "Quantum size: ");
|
||||||
write_cb(cbopaque, umax2s(sv, 10, s));
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
write_cb(cbopaque, "\n");
|
write_cb(cbopaque, "\n");
|
||||||
|
|
||||||
CTL_GET("arenas.cacheline", &sv, size_t);
|
CTL_GET("arenas.cacheline", &sv, size_t);
|
||||||
write_cb(cbopaque, "Cacheline size (assumed): ");
|
write_cb(cbopaque, "Cacheline size (assumed): ");
|
||||||
write_cb(cbopaque, umax2s(sv, 10, s));
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
write_cb(cbopaque, "\n");
|
write_cb(cbopaque, "\n");
|
||||||
|
|
||||||
CTL_GET("arenas.subpage", &sv, size_t);
|
CTL_GET("arenas.subpage", &sv, size_t);
|
||||||
write_cb(cbopaque, "Subpage spacing: ");
|
write_cb(cbopaque, "Subpage spacing: ");
|
||||||
write_cb(cbopaque, umax2s(sv, 10, s));
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
write_cb(cbopaque, "\n");
|
write_cb(cbopaque, "\n");
|
||||||
|
|
||||||
if ((err = JEMALLOC_P(mallctl)("arenas.tspace_min", &sv, &ssz,
|
if ((err = JEMALLOC_P(mallctl)("arenas.tspace_min", &sv, &ssz,
|
||||||
NULL, 0)) == 0) {
|
NULL, 0)) == 0) {
|
||||||
write_cb(cbopaque, "Tiny 2^n-spaced sizes: [");
|
write_cb(cbopaque, "Tiny 2^n-spaced sizes: [");
|
||||||
write_cb(cbopaque, umax2s(sv, 10, s));
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
write_cb(cbopaque, "..");
|
write_cb(cbopaque, "..");
|
||||||
|
|
||||||
CTL_GET("arenas.tspace_max", &sv, size_t);
|
CTL_GET("arenas.tspace_max", &sv, size_t);
|
||||||
write_cb(cbopaque, umax2s(sv, 10, s));
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
write_cb(cbopaque, "]\n");
|
write_cb(cbopaque, "]\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
CTL_GET("arenas.qspace_min", &sv, size_t);
|
CTL_GET("arenas.qspace_min", &sv, size_t);
|
||||||
write_cb(cbopaque, "Quantum-spaced sizes: [");
|
write_cb(cbopaque, "Quantum-spaced sizes: [");
|
||||||
write_cb(cbopaque, umax2s(sv, 10, s));
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
write_cb(cbopaque, "..");
|
write_cb(cbopaque, "..");
|
||||||
CTL_GET("arenas.qspace_max", &sv, size_t);
|
CTL_GET("arenas.qspace_max", &sv, size_t);
|
||||||
write_cb(cbopaque, umax2s(sv, 10, s));
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
write_cb(cbopaque, "]\n");
|
write_cb(cbopaque, "]\n");
|
||||||
|
|
||||||
CTL_GET("arenas.cspace_min", &sv, size_t);
|
CTL_GET("arenas.cspace_min", &sv, size_t);
|
||||||
write_cb(cbopaque, "Cacheline-spaced sizes: [");
|
write_cb(cbopaque, "Cacheline-spaced sizes: [");
|
||||||
write_cb(cbopaque, umax2s(sv, 10, s));
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
write_cb(cbopaque, "..");
|
write_cb(cbopaque, "..");
|
||||||
CTL_GET("arenas.cspace_max", &sv, size_t);
|
CTL_GET("arenas.cspace_max", &sv, size_t);
|
||||||
write_cb(cbopaque, umax2s(sv, 10, s));
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
write_cb(cbopaque, "]\n");
|
write_cb(cbopaque, "]\n");
|
||||||
|
|
||||||
CTL_GET("arenas.sspace_min", &sv, size_t);
|
CTL_GET("arenas.sspace_min", &sv, size_t);
|
||||||
write_cb(cbopaque, "Subpage-spaced sizes: [");
|
write_cb(cbopaque, "Subpage-spaced sizes: [");
|
||||||
write_cb(cbopaque, umax2s(sv, 10, s));
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
write_cb(cbopaque, "..");
|
write_cb(cbopaque, "..");
|
||||||
CTL_GET("arenas.sspace_max", &sv, size_t);
|
CTL_GET("arenas.sspace_max", &sv, size_t);
|
||||||
write_cb(cbopaque, umax2s(sv, 10, s));
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
write_cb(cbopaque, "]\n");
|
write_cb(cbopaque, "]\n");
|
||||||
|
|
||||||
CTL_GET("opt.lg_dirty_mult", &ssv, ssize_t);
|
CTL_GET("opt.lg_dirty_mult", &ssv, ssize_t);
|
||||||
if (ssv >= 0) {
|
if (ssv >= 0) {
|
||||||
write_cb(cbopaque,
|
write_cb(cbopaque,
|
||||||
"Min active:dirty page ratio per arena: ");
|
"Min active:dirty page ratio per arena: ");
|
||||||
write_cb(cbopaque, umax2s((1U << ssv), 10, s));
|
write_cb(cbopaque, u2s((1U << ssv), 10, s));
|
||||||
write_cb(cbopaque, ":1\n");
|
write_cb(cbopaque, ":1\n");
|
||||||
} else {
|
} else {
|
||||||
write_cb(cbopaque,
|
write_cb(cbopaque,
|
||||||
@@ -560,7 +616,7 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
|
|||||||
&ssz, NULL, 0)) == 0) {
|
&ssz, NULL, 0)) == 0) {
|
||||||
write_cb(cbopaque,
|
write_cb(cbopaque,
|
||||||
"Maximum thread-cached size class: ");
|
"Maximum thread-cached size class: ");
|
||||||
write_cb(cbopaque, umax2s(sv, 10, s));
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
write_cb(cbopaque, "\n");
|
write_cb(cbopaque, "\n");
|
||||||
}
|
}
|
||||||
if ((err = JEMALLOC_P(mallctl)("opt.lg_tcache_gc_sweep", &ssv,
|
if ((err = JEMALLOC_P(mallctl)("opt.lg_tcache_gc_sweep", &ssv,
|
||||||
@@ -570,60 +626,77 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
|
|||||||
CTL_GET("opt.tcache", &tcache_enabled, bool);
|
CTL_GET("opt.tcache", &tcache_enabled, bool);
|
||||||
write_cb(cbopaque, "Thread cache GC sweep interval: ");
|
write_cb(cbopaque, "Thread cache GC sweep interval: ");
|
||||||
write_cb(cbopaque, tcache_enabled && ssv >= 0 ?
|
write_cb(cbopaque, tcache_enabled && ssv >= 0 ?
|
||||||
umax2s(tcache_gc_sweep, 10, s) : "N/A");
|
u2s(tcache_gc_sweep, 10, s) : "N/A");
|
||||||
write_cb(cbopaque, "\n");
|
write_cb(cbopaque, "\n");
|
||||||
}
|
}
|
||||||
if ((err = JEMALLOC_P(mallctl)("opt.prof", &bv, &bsz, NULL, 0))
|
if ((err = JEMALLOC_P(mallctl)("opt.prof", &bv, &bsz, NULL, 0))
|
||||||
== 0 && bv) {
|
== 0 && bv) {
|
||||||
CTL_GET("opt.lg_prof_bt_max", &sv, size_t);
|
CTL_GET("opt.lg_prof_bt_max", &sv, size_t);
|
||||||
write_cb(cbopaque, "Maximum profile backtrace depth: ");
|
write_cb(cbopaque, "Maximum profile backtrace depth: ");
|
||||||
write_cb(cbopaque, umax2s((1U << sv), 10, s));
|
write_cb(cbopaque, u2s((1U << sv), 10, s));
|
||||||
write_cb(cbopaque, "\n");
|
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);
|
CTL_GET("opt.lg_prof_sample", &sv, size_t);
|
||||||
write_cb(cbopaque, "Average profile sample interval: ");
|
write_cb(cbopaque, "Average profile sample interval: ");
|
||||||
write_cb(cbopaque, umax2s((1U << sv), 10, s));
|
write_cb(cbopaque, u2s((((uint64_t)1U) << sv), 10, s));
|
||||||
write_cb(cbopaque, " (2^");
|
write_cb(cbopaque, " (2^");
|
||||||
write_cb(cbopaque, umax2s(sv, 10, s));
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
write_cb(cbopaque, ")\n");
|
write_cb(cbopaque, ")\n");
|
||||||
|
|
||||||
CTL_GET("opt.lg_prof_interval", &ssv, ssize_t);
|
CTL_GET("opt.lg_prof_interval", &ssv, ssize_t);
|
||||||
write_cb(cbopaque, "Average profile dump interval: ");
|
write_cb(cbopaque, "Average profile dump interval: ");
|
||||||
if (ssv >= 0) {
|
if (ssv >= 0) {
|
||||||
write_cb(cbopaque, umax2s((1U << ssv), 10, s));
|
write_cb(cbopaque, u2s((((uint64_t)1U) << ssv),
|
||||||
|
10, s));
|
||||||
write_cb(cbopaque, " (2^");
|
write_cb(cbopaque, " (2^");
|
||||||
write_cb(cbopaque, umax2s(ssv, 10, s));
|
write_cb(cbopaque, u2s(ssv, 10, s));
|
||||||
write_cb(cbopaque, ")\n");
|
write_cb(cbopaque, ")\n");
|
||||||
} else
|
} else
|
||||||
write_cb(cbopaque, "N/A\n");
|
write_cb(cbopaque, "N/A\n");
|
||||||
}
|
}
|
||||||
CTL_GET("arenas.chunksize", &sv, size_t);
|
CTL_GET("arenas.chunksize", &sv, size_t);
|
||||||
write_cb(cbopaque, "Chunk size: ");
|
write_cb(cbopaque, "Chunk size: ");
|
||||||
write_cb(cbopaque, umax2s(sv, 10, s));
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
CTL_GET("opt.lg_chunk", &sv, size_t);
|
CTL_GET("opt.lg_chunk", &sv, size_t);
|
||||||
write_cb(cbopaque, " (2^");
|
write_cb(cbopaque, " (2^");
|
||||||
write_cb(cbopaque, umax2s(sv, 10, s));
|
write_cb(cbopaque, u2s(sv, 10, s));
|
||||||
write_cb(cbopaque, ")\n");
|
write_cb(cbopaque, ")\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JEMALLOC_STATS
|
#ifdef JEMALLOC_STATS
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
size_t ssz;
|
size_t sszp, ssz;
|
||||||
|
size_t *cactive;
|
||||||
size_t allocated, active, mapped;
|
size_t allocated, active, mapped;
|
||||||
size_t chunks_current, chunks_high, swap_avail;
|
size_t chunks_current, chunks_high, swap_avail;
|
||||||
uint64_t chunks_total;
|
uint64_t chunks_total;
|
||||||
size_t huge_allocated;
|
size_t huge_allocated;
|
||||||
uint64_t huge_nmalloc, huge_ndalloc;
|
uint64_t huge_nmalloc, huge_ndalloc;
|
||||||
|
|
||||||
|
sszp = sizeof(size_t *);
|
||||||
ssz = sizeof(size_t);
|
ssz = sizeof(size_t);
|
||||||
|
|
||||||
|
CTL_GET("stats.cactive", &cactive, size_t *);
|
||||||
CTL_GET("stats.allocated", &allocated, size_t);
|
CTL_GET("stats.allocated", &allocated, size_t);
|
||||||
CTL_GET("stats.active", &active, size_t);
|
CTL_GET("stats.active", &active, size_t);
|
||||||
CTL_GET("stats.mapped", &mapped, size_t);
|
CTL_GET("stats.mapped", &mapped, size_t);
|
||||||
malloc_cprintf(write_cb, cbopaque,
|
malloc_cprintf(write_cb, cbopaque,
|
||||||
"Allocated: %zu, active: %zu, mapped: %zu\n", allocated,
|
"Allocated: %zu, active: %zu, mapped: %zu\n",
|
||||||
active, mapped);
|
allocated, active, mapped);
|
||||||
|
malloc_cprintf(write_cb, cbopaque,
|
||||||
|
"Current active ceiling: %zu\n", atomic_read_z(cactive));
|
||||||
|
|
||||||
/* Print chunk stats. */
|
/* Print chunk stats. */
|
||||||
CTL_GET("stats.chunks.total", &chunks_total, uint64_t);
|
CTL_GET("stats.chunks.total", &chunks_total, uint64_t);
|
||||||
@@ -5,17 +5,22 @@
|
|||||||
/* Data. */
|
/* Data. */
|
||||||
|
|
||||||
bool opt_tcache = true;
|
bool opt_tcache = true;
|
||||||
ssize_t opt_lg_tcache_maxclass = LG_TCACHE_MAXCLASS_DEFAULT;
|
ssize_t opt_lg_tcache_max = LG_TCACHE_MAXCLASS_DEFAULT;
|
||||||
ssize_t opt_lg_tcache_gc_sweep = LG_TCACHE_GC_SWEEP_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. */
|
/* Map of thread-specific caches. */
|
||||||
|
#ifndef NO_TLS
|
||||||
__thread tcache_t *tcache_tls JEMALLOC_ATTR(tls_model("initial-exec"));
|
__thread tcache_t *tcache_tls JEMALLOC_ATTR(tls_model("initial-exec"));
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Same contents as tcache, but initialized such that the TSD destructor is
|
* 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.
|
* called when a thread exits, so that the cache can be cleaned up.
|
||||||
*/
|
*/
|
||||||
static pthread_key_t tcache_tsd;
|
pthread_key_t tcache_tsd;
|
||||||
|
|
||||||
size_t nhbins;
|
size_t nhbins;
|
||||||
size_t tcache_maxclass;
|
size_t tcache_maxclass;
|
||||||
@@ -53,18 +58,19 @@ tcache_bin_flush_small(tcache_bin_t *tbin, size_t binind, unsigned rem
|
|||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
void *flush, *deferred, *ptr;
|
void *ptr;
|
||||||
unsigned i, nflush, ndeferred;
|
unsigned i, nflush, ndeferred;
|
||||||
bool first_pass;
|
#ifdef JEMALLOC_STATS
|
||||||
|
bool merged_stats = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
assert(binind < nbins);
|
assert(binind < nbins);
|
||||||
assert(rem <= tbin->ncached);
|
assert(rem <= tbin->ncached);
|
||||||
assert(tbin->ncached > 0 || tbin->avail == NULL);
|
|
||||||
|
|
||||||
for (flush = tbin->avail, nflush = tbin->ncached - rem, first_pass =
|
for (nflush = tbin->ncached - rem; nflush > 0; nflush = ndeferred) {
|
||||||
true; flush != NULL; flush = deferred, nflush = ndeferred) {
|
|
||||||
/* Lock the arena bin associated with the first object. */
|
/* Lock the arena bin associated with the first object. */
|
||||||
arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(flush);
|
arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(
|
||||||
|
tbin->avail[0]);
|
||||||
arena_t *arena = chunk->arena;
|
arena_t *arena = chunk->arena;
|
||||||
arena_bin_t *bin = &arena->bins[binind];
|
arena_bin_t *bin = &arena->bins[binind];
|
||||||
|
|
||||||
@@ -80,23 +86,23 @@ tcache_bin_flush_small(tcache_bin_t *tbin, size_t binind, unsigned rem
|
|||||||
malloc_mutex_lock(&bin->lock);
|
malloc_mutex_lock(&bin->lock);
|
||||||
#ifdef JEMALLOC_STATS
|
#ifdef JEMALLOC_STATS
|
||||||
if (arena == tcache->arena) {
|
if (arena == tcache->arena) {
|
||||||
|
assert(merged_stats == false);
|
||||||
|
merged_stats = true;
|
||||||
bin->stats.nflushes++;
|
bin->stats.nflushes++;
|
||||||
bin->stats.nrequests += tbin->tstats.nrequests;
|
bin->stats.nrequests += tbin->tstats.nrequests;
|
||||||
tbin->tstats.nrequests = 0;
|
tbin->tstats.nrequests = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
deferred = NULL;
|
|
||||||
ndeferred = 0;
|
ndeferred = 0;
|
||||||
for (i = 0; i < nflush; i++) {
|
for (i = 0; i < nflush; i++) {
|
||||||
ptr = flush;
|
ptr = tbin->avail[i];
|
||||||
assert(ptr != NULL);
|
assert(ptr != NULL);
|
||||||
flush = *(void **)ptr;
|
|
||||||
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
||||||
if (chunk->arena == arena) {
|
if (chunk->arena == arena) {
|
||||||
size_t pageind = (((uintptr_t)ptr -
|
size_t pageind = ((uintptr_t)ptr -
|
||||||
(uintptr_t)chunk) >> PAGE_SHIFT);
|
(uintptr_t)chunk) >> PAGE_SHIFT;
|
||||||
arena_chunk_map_t *mapelm =
|
arena_chunk_map_t *mapelm =
|
||||||
&chunk->map[pageind];
|
&chunk->map[pageind-map_bias];
|
||||||
arena_dalloc_bin(arena, chunk, ptr, mapelm);
|
arena_dalloc_bin(arena, chunk, ptr, mapelm);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
@@ -105,21 +111,31 @@ tcache_bin_flush_small(tcache_bin_t *tbin, size_t binind, unsigned rem
|
|||||||
* locked. Stash the object, so that it can be
|
* locked. Stash the object, so that it can be
|
||||||
* handled in a future pass.
|
* handled in a future pass.
|
||||||
*/
|
*/
|
||||||
*(void **)ptr = deferred;
|
tbin->avail[ndeferred] = ptr;
|
||||||
deferred = ptr;
|
|
||||||
ndeferred++;
|
ndeferred++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
malloc_mutex_unlock(&bin->lock);
|
malloc_mutex_unlock(&bin->lock);
|
||||||
|
|
||||||
if (first_pass) {
|
|
||||||
tbin->avail = flush;
|
|
||||||
first_pass = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#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;
|
tbin->ncached = rem;
|
||||||
if (tbin->ncached < tbin->low_water)
|
if ((int)tbin->ncached < tbin->low_water)
|
||||||
tbin->low_water = tbin->ncached;
|
tbin->low_water = tbin->ncached;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,18 +146,19 @@ tcache_bin_flush_large(tcache_bin_t *tbin, size_t binind, unsigned rem
|
|||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
void *flush, *deferred, *ptr;
|
void *ptr;
|
||||||
unsigned i, nflush, ndeferred;
|
unsigned i, nflush, ndeferred;
|
||||||
bool first_pass;
|
#ifdef JEMALLOC_STATS
|
||||||
|
bool merged_stats = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
assert(binind < nhbins);
|
assert(binind < nhbins);
|
||||||
assert(rem <= tbin->ncached);
|
assert(rem <= tbin->ncached);
|
||||||
assert(tbin->ncached > 0 || tbin->avail == NULL);
|
|
||||||
|
|
||||||
for (flush = tbin->avail, nflush = tbin->ncached - rem, first_pass =
|
for (nflush = tbin->ncached - rem; nflush > 0; nflush = ndeferred) {
|
||||||
true; flush != NULL; flush = deferred, nflush = ndeferred) {
|
|
||||||
/* Lock the arena associated with the first object. */
|
/* Lock the arena associated with the first object. */
|
||||||
arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(flush);
|
arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(
|
||||||
|
tbin->avail[0]);
|
||||||
arena_t *arena = chunk->arena;
|
arena_t *arena = chunk->arena;
|
||||||
|
|
||||||
malloc_mutex_lock(&arena->lock);
|
malloc_mutex_lock(&arena->lock);
|
||||||
@@ -153,6 +170,7 @@ tcache_bin_flush_large(tcache_bin_t *tbin, size_t binind, unsigned rem
|
|||||||
tcache->prof_accumbytes = 0;
|
tcache->prof_accumbytes = 0;
|
||||||
#endif
|
#endif
|
||||||
#ifdef JEMALLOC_STATS
|
#ifdef JEMALLOC_STATS
|
||||||
|
merged_stats = true;
|
||||||
arena->stats.nrequests_large += tbin->tstats.nrequests;
|
arena->stats.nrequests_large += tbin->tstats.nrequests;
|
||||||
arena->stats.lstats[binind - nbins].nrequests +=
|
arena->stats.lstats[binind - nbins].nrequests +=
|
||||||
tbin->tstats.nrequests;
|
tbin->tstats.nrequests;
|
||||||
@@ -161,12 +179,10 @@ tcache_bin_flush_large(tcache_bin_t *tbin, size_t binind, unsigned rem
|
|||||||
#if (defined(JEMALLOC_PROF) || defined(JEMALLOC_STATS))
|
#if (defined(JEMALLOC_PROF) || defined(JEMALLOC_STATS))
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
deferred = NULL;
|
|
||||||
ndeferred = 0;
|
ndeferred = 0;
|
||||||
for (i = 0; i < nflush; i++) {
|
for (i = 0; i < nflush; i++) {
|
||||||
ptr = flush;
|
ptr = tbin->avail[i];
|
||||||
assert(ptr != NULL);
|
assert(ptr != NULL);
|
||||||
flush = *(void **)ptr;
|
|
||||||
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
||||||
if (chunk->arena == arena)
|
if (chunk->arena == arena)
|
||||||
arena_dalloc_large(arena, chunk, ptr);
|
arena_dalloc_large(arena, chunk, ptr);
|
||||||
@@ -177,21 +193,32 @@ tcache_bin_flush_large(tcache_bin_t *tbin, size_t binind, unsigned rem
|
|||||||
* Stash the object, so that it can be handled
|
* Stash the object, so that it can be handled
|
||||||
* in a future pass.
|
* in a future pass.
|
||||||
*/
|
*/
|
||||||
*(void **)ptr = deferred;
|
tbin->avail[ndeferred] = ptr;
|
||||||
deferred = ptr;
|
|
||||||
ndeferred++;
|
ndeferred++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
malloc_mutex_unlock(&arena->lock);
|
malloc_mutex_unlock(&arena->lock);
|
||||||
|
|
||||||
if (first_pass) {
|
|
||||||
tbin->avail = flush;
|
|
||||||
first_pass = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#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;
|
tbin->ncached = rem;
|
||||||
if (tbin->ncached < tbin->low_water)
|
if ((int)tbin->ncached < tbin->low_water)
|
||||||
tbin->low_water = tbin->ncached;
|
tbin->low_water = tbin->ncached;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,20 +226,28 @@ tcache_t *
|
|||||||
tcache_create(arena_t *arena)
|
tcache_create(arena_t *arena)
|
||||||
{
|
{
|
||||||
tcache_t *tcache;
|
tcache_t *tcache;
|
||||||
size_t size;
|
size_t size, stack_offset;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
size = sizeof(tcache_t) + (sizeof(tcache_bin_t) * (nhbins - 1));
|
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
|
* Round up to the nearest multiple of the cacheline size, in order to
|
||||||
* avoid the possibility of false cacheline sharing.
|
* avoid the possibility of false cacheline sharing.
|
||||||
*
|
*
|
||||||
* That this works relies on the same logic as in ipalloc().
|
* 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);
|
size = (size + CACHELINE_MASK) & (-CACHELINE);
|
||||||
|
|
||||||
if (size <= small_maxclass)
|
if (size <= small_maxclass)
|
||||||
tcache = (tcache_t *)arena_malloc_small(arena, size, true);
|
tcache = (tcache_t *)arena_malloc_small(arena, size, true);
|
||||||
|
else if (size <= tcache_maxclass)
|
||||||
|
tcache = (tcache_t *)arena_malloc_large(arena, size, true);
|
||||||
else
|
else
|
||||||
tcache = (tcache_t *)icalloc(size);
|
tcache = (tcache_t *)icalloc(size);
|
||||||
|
|
||||||
@@ -229,18 +264,14 @@ tcache_create(arena_t *arena)
|
|||||||
|
|
||||||
tcache->arena = arena;
|
tcache->arena = arena;
|
||||||
assert((TCACHE_NSLOTS_SMALL_MAX & 1U) == 0);
|
assert((TCACHE_NSLOTS_SMALL_MAX & 1U) == 0);
|
||||||
for (i = 0; i < nbins; i++) {
|
for (i = 0; i < nhbins; i++) {
|
||||||
if ((arena->bins[i].nregs << 1) <= TCACHE_NSLOTS_SMALL_MAX) {
|
tcache->tbins[i].lg_fill_div = 1;
|
||||||
tcache->tbins[i].ncached_max = (arena->bins[i].nregs <<
|
tcache->tbins[i].avail = (void **)((uintptr_t)tcache +
|
||||||
1);
|
(uintptr_t)stack_offset);
|
||||||
} else
|
stack_offset += tcache_bin_info[i].ncached_max * sizeof(void *);
|
||||||
tcache->tbins[i].ncached_max = TCACHE_NSLOTS_SMALL_MAX;
|
|
||||||
}
|
}
|
||||||
for (; i < nhbins; i++)
|
|
||||||
tcache->tbins[i].ncached_max = TCACHE_NSLOTS_LARGE;
|
|
||||||
|
|
||||||
tcache_tls = tcache;
|
TCACHE_SET(tcache);
|
||||||
pthread_setspecific(tcache_tsd, tcache);
|
|
||||||
|
|
||||||
return (tcache);
|
return (tcache);
|
||||||
}
|
}
|
||||||
@@ -249,6 +280,7 @@ void
|
|||||||
tcache_destroy(tcache_t *tcache)
|
tcache_destroy(tcache_t *tcache)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
size_t tcache_size;
|
||||||
|
|
||||||
#ifdef JEMALLOC_STATS
|
#ifdef JEMALLOC_STATS
|
||||||
/* Unlink from list of extant tcaches. */
|
/* Unlink from list of extant tcaches. */
|
||||||
@@ -305,12 +337,13 @@ tcache_destroy(tcache_t *tcache)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (arena_salloc(tcache) <= small_maxclass) {
|
tcache_size = arena_salloc(tcache);
|
||||||
|
if (tcache_size <= small_maxclass) {
|
||||||
arena_chunk_t *chunk = CHUNK_ADDR2BASE(tcache);
|
arena_chunk_t *chunk = CHUNK_ADDR2BASE(tcache);
|
||||||
arena_t *arena = chunk->arena;
|
arena_t *arena = chunk->arena;
|
||||||
size_t pageind = (((uintptr_t)tcache - (uintptr_t)chunk) >>
|
size_t pageind = ((uintptr_t)tcache - (uintptr_t)chunk) >>
|
||||||
PAGE_SHIFT);
|
PAGE_SHIFT;
|
||||||
arena_chunk_map_t *mapelm = &chunk->map[pageind];
|
arena_chunk_map_t *mapelm = &chunk->map[pageind-map_bias];
|
||||||
arena_run_t *run = (arena_run_t *)((uintptr_t)chunk +
|
arena_run_t *run = (arena_run_t *)((uintptr_t)chunk +
|
||||||
(uintptr_t)((pageind - (mapelm->bits >> PAGE_SHIFT)) <<
|
(uintptr_t)((pageind - (mapelm->bits >> PAGE_SHIFT)) <<
|
||||||
PAGE_SHIFT));
|
PAGE_SHIFT));
|
||||||
@@ -319,6 +352,13 @@ tcache_destroy(tcache_t *tcache)
|
|||||||
malloc_mutex_lock(&bin->lock);
|
malloc_mutex_lock(&bin->lock);
|
||||||
arena_dalloc_bin(arena, chunk, tcache, mapelm);
|
arena_dalloc_bin(arena, chunk, tcache, mapelm);
|
||||||
malloc_mutex_unlock(&bin->lock);
|
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
|
} else
|
||||||
idalloc(tcache);
|
idalloc(tcache);
|
||||||
}
|
}
|
||||||
@@ -328,11 +368,24 @@ tcache_thread_cleanup(void *arg)
|
|||||||
{
|
{
|
||||||
tcache_t *tcache = (tcache_t *)arg;
|
tcache_t *tcache = (tcache_t *)arg;
|
||||||
|
|
||||||
assert(tcache == tcache_tls);
|
if (tcache == (void *)(uintptr_t)1) {
|
||||||
if (tcache != NULL) {
|
/*
|
||||||
|
* 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);
|
assert(tcache != (void *)(uintptr_t)1);
|
||||||
tcache_destroy(tcache);
|
tcache_destroy(tcache);
|
||||||
tcache_tls = (void *)(uintptr_t)1;
|
TCACHE_SET((uintptr_t)1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,25 +415,49 @@ tcache_stats_merge(tcache_t *tcache, arena_t *arena)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void
|
bool
|
||||||
tcache_boot(void)
|
tcache_boot(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (opt_tcache) {
|
if (opt_tcache) {
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If necessary, clamp opt_lg_tcache_maxclass, now that
|
* If necessary, clamp opt_lg_tcache_max, now that
|
||||||
* small_maxclass and arena_maxclass are known.
|
* small_maxclass and arena_maxclass are known.
|
||||||
*/
|
*/
|
||||||
if (opt_lg_tcache_maxclass < 0 || (1U <<
|
if (opt_lg_tcache_max < 0 || (1U <<
|
||||||
opt_lg_tcache_maxclass) < small_maxclass)
|
opt_lg_tcache_max) < small_maxclass)
|
||||||
tcache_maxclass = small_maxclass;
|
tcache_maxclass = small_maxclass;
|
||||||
else if ((1U << opt_lg_tcache_maxclass) > arena_maxclass)
|
else if ((1U << opt_lg_tcache_max) > arena_maxclass)
|
||||||
tcache_maxclass = arena_maxclass;
|
tcache_maxclass = arena_maxclass;
|
||||||
else
|
else
|
||||||
tcache_maxclass = (1U << opt_lg_tcache_maxclass);
|
tcache_maxclass = (1U << opt_lg_tcache_max);
|
||||||
|
|
||||||
nhbins = nbins + (tcache_maxclass >> PAGE_SHIFT);
|
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. */
|
/* Compute incremental GC event threshold. */
|
||||||
if (opt_lg_tcache_gc_sweep >= 0) {
|
if (opt_lg_tcache_gc_sweep >= 0) {
|
||||||
tcache_gc_incr = ((1U << opt_lg_tcache_gc_sweep) /
|
tcache_gc_incr = ((1U << opt_lg_tcache_gc_sweep) /
|
||||||
@@ -396,6 +473,8 @@ tcache_boot(void)
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (false);
|
||||||
}
|
}
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
#endif /* JEMALLOC_TCACHE */
|
#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