mirror of
https://github.com/jemalloc/jemalloc.git
synced 2026-07-22 04:03:11 +00:00
Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb4e26aa9e | ||
|
|
4bcd987251 | ||
|
|
38d9210c46 | ||
|
|
eacb896c01 | ||
|
|
c957398b4f | ||
|
|
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 |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -3,6 +3,10 @@
|
||||
/jemalloc/config.log
|
||||
/jemalloc/config.status
|
||||
/jemalloc/configure
|
||||
/jemalloc/doc/html.xsl
|
||||
/jemalloc/doc/manpages.xsl
|
||||
/jemalloc/doc/jemalloc.xml
|
||||
/jemalloc/doc/jemalloc.html
|
||||
/jemalloc/doc/jemalloc.3
|
||||
/jemalloc/lib/
|
||||
/jemalloc/Makefile
|
||||
@@ -13,4 +17,7 @@
|
||||
/jemalloc/src/*.[od]
|
||||
/jemalloc/test/*.[od]
|
||||
/jemalloc/test/*.out
|
||||
/jemalloc/test/[a-z]*
|
||||
!/jemalloc/test/*.c
|
||||
!/jemalloc/test/*.exp
|
||||
/jemalloc/VERSION
|
||||
|
||||
@@ -6,42 +6,118 @@ found in the git revision history:
|
||||
http://www.canonware.com/cgi-bin/gitweb.cgi?p=jemalloc.git
|
||||
git://canonware.com/jemalloc.git
|
||||
|
||||
* 2.0.0
|
||||
* 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.
|
||||
- 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.
|
||||
- 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
|
||||
@@ -59,7 +135,7 @@ found in the git revision history:
|
||||
- Fix a heap profiling bug due to sometimes losing track of requested object
|
||||
size for sampled objects.
|
||||
|
||||
* 1.0.3
|
||||
* 1.0.3 (August 12, 2010)
|
||||
|
||||
Bug fixes:
|
||||
- Fix the libunwind-based implementation of stack backtracing (used for heap
|
||||
@@ -68,7 +144,7 @@ found in the git revision history:
|
||||
threads raced to initialize malloc, some of them could end up permanently
|
||||
blocked.
|
||||
|
||||
* 1.0.2
|
||||
* 1.0.2 (May 11, 2010)
|
||||
|
||||
Bug fixes:
|
||||
- Fix junk filling of large objects, which could cause memory corruption.
|
||||
@@ -76,7 +152,7 @@ found in the git revision history:
|
||||
memory limits could cause swap file configuration to fail. Contributed by
|
||||
Jordan DeLong.
|
||||
|
||||
* 1.0.1
|
||||
* 1.0.1 (April 14, 2010)
|
||||
|
||||
Bug fixes:
|
||||
- Fix compilation when --enable-fill is specified.
|
||||
@@ -85,7 +161,7 @@ found in the git revision history:
|
||||
- Fix dirty page purging race conditions that could cause crashes.
|
||||
- Fix crash in tcache flushing code during thread destruction.
|
||||
|
||||
* 1.0.0
|
||||
* 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
|
||||
@@ -121,7 +197,7 @@ found in the git revision history:
|
||||
- Fix a chunk leak. The leaked chunks were never touched, so this impacted
|
||||
virtual memory usage, but not physical memory usage.
|
||||
|
||||
* linux_20080828a, linux_20080827a
|
||||
* 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.
|
||||
|
||||
@@ -28,7 +28,7 @@ any of the following arguments (not a definitive list) to 'configure':
|
||||
|
||||
--with-jemalloc-prefix=<prefix>
|
||||
Prefix all public APIs with <prefix>. For example, if <prefix> is
|
||||
"prefix_", the API changes like the following occur:
|
||||
"prefix_", API changes like the following occur:
|
||||
|
||||
malloc() --> prefix_malloc()
|
||||
malloc_conf --> prefix_malloc_conf
|
||||
@@ -48,9 +48,9 @@ any of the following arguments (not a definitive list) to 'configure':
|
||||
example, libjemalloc.so.0 becomes libjemalloc<suffix>.so.0.
|
||||
|
||||
--enable-cc-silence
|
||||
Enable code that silences unuseful 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 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 assertions and validation code. This incurs a substantial
|
||||
@@ -62,18 +62,23 @@ any of the following arguments (not a definitive list) to 'configure':
|
||||
|
||||
--enable-prof
|
||||
Enable heap profiling and leak detection functionality. See the "opt.prof"
|
||||
option documention for usage details.
|
||||
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
|
||||
Disable the use of libgcc's backtracing functionality. Ordinarily, libgcc's
|
||||
backtracing functionality is superior to the alternatives, but it may fail
|
||||
to capture backtraces on some systems.
|
||||
+ libunwind (requires --enable-prof-libunwind)
|
||||
+ libgcc (unless --disable-prof-libgcc)
|
||||
+ gcc intrinsics (unless --disable-prof-gcc)
|
||||
|
||||
--enable-prof-libunwind
|
||||
Use the libunwind library (http://www.nongnu.org/libunwind/) for stack
|
||||
backtracing. libunwind is quite slow, but it tends to work across a wider
|
||||
variety of system configurations than the default backtracing code, which is
|
||||
based on libgcc functionality or gcc intrinsics.
|
||||
backtracing.
|
||||
|
||||
--disable-prof-libgcc
|
||||
Disable the use of libgcc's backtracing functionality.
|
||||
|
||||
--disable-prof-gcc
|
||||
Disable the use of gcc intrinsics for backtracing.
|
||||
|
||||
--with-static-libunwind=<libunwind.a>
|
||||
Statically link against the specified libunwind.a rather than dynamically
|
||||
@@ -89,7 +94,7 @@ any of the following arguments (not a definitive list) to 'configure':
|
||||
--disable-tcache
|
||||
Disable thread-specific caches for small objects. Objects are cached and
|
||||
released in bulk, thus reducing the total number of mutex operations. See
|
||||
the "opt.tcache" option for suage details.
|
||||
the "opt.tcache" option for usage details.
|
||||
|
||||
--enable-swap
|
||||
Enable mmap()ed swap file support. When this feature is built in, it is
|
||||
@@ -132,8 +137,11 @@ any of the following arguments (not a definitive list) to 'configure':
|
||||
--disable-tls
|
||||
Disable thread-local storage (TLS), which allows for fast access to
|
||||
thread-local variables via the __thread keyword. If TLS is available,
|
||||
jemalloc uses it for several purposes. Note that disabling TLS implies
|
||||
--disable-tcache.
|
||||
jemalloc uses it for several purposes.
|
||||
|
||||
--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
|
||||
behavior:
|
||||
@@ -172,7 +180,7 @@ To install only parts of jemalloc, use the following targets:
|
||||
install_bin
|
||||
install_include
|
||||
install_lib
|
||||
install_man
|
||||
install_doc
|
||||
|
||||
To clean up build results to varying degrees, use the following make targets:
|
||||
|
||||
@@ -195,8 +203,8 @@ MANDIR="?"
|
||||
Use this as the installation prefix for man pages.
|
||||
|
||||
DESTDIR="?"
|
||||
Prepend DESTDIR to INCLUDEDIR, LIBDIR, and MANDIR. This is useful when
|
||||
installing to a different path than was specified via --prefix.
|
||||
Prepend DESTDIR to INCLUDEDIR, LIBDIR, DATADIR, and MANDIR. This is useful
|
||||
when installing to a different path than was specified via --prefix.
|
||||
|
||||
CC="?"
|
||||
Use this to invoke the C compiler.
|
||||
@@ -232,11 +240,12 @@ directory, issue configuration and build commands:
|
||||
|
||||
=== Documentation ==============================================================
|
||||
|
||||
The manual page that the configure script generates can be manually formatted
|
||||
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 -man-ext -t doc/jemalloc.3
|
||||
nroff -man -t doc/jemalloc.3
|
||||
|
||||
groff -man -man-ext -t -Tps doc/jemalloc.3 | ps2pdf - doc/jemalloc.3.pdf
|
||||
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)
|
||||
|
||||
@@ -15,11 +15,12 @@ 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@ -fPIC -DPIC
|
||||
CFLAGS := @CFLAGS@
|
||||
ifeq (macho, @abi@)
|
||||
CFLAGS += -dynamic
|
||||
endif
|
||||
@@ -44,48 +45,82 @@ endif
|
||||
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/rtree.c \
|
||||
@srcroot@src/stats.c @srcroot@src/tcache.c
|
||||
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/posix_memalign.c \
|
||||
@srcroot@test/rallocm.c @srcroot@test/thread_arena.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 install check clean distclean relclean
|
||||
.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)
|
||||
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@%.o)
|
||||
@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@%.o)
|
||||
@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 $@ $+
|
||||
|
||||
@@ -94,6 +129,9 @@ all: $(DSOS)
|
||||
$(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)
|
||||
@@ -117,20 +155,30 @@ install_include:
|
||||
install -m 644 $$h $(INCLUDEDIR)/jemalloc; \
|
||||
done
|
||||
|
||||
install_lib: $(DSOS)
|
||||
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 m in $(MAN3); do \
|
||||
echo "install -m 644 $$m $(MANDIR)/man3"; \
|
||||
install -m 644 $$m $(MANDIR)/man3; \
|
||||
@for d in $(DOCS_MAN3); do \
|
||||
echo "install -m 644 $$d $(MANDIR)/man3"; \
|
||||
install -m 644 $$d $(MANDIR)/man3; \
|
||||
done
|
||||
|
||||
install: install_bin install_include install_lib install_man
|
||||
install_doc: install_html install_man
|
||||
|
||||
install: install_bin install_include install_lib install_doc
|
||||
|
||||
tests: $(CTESTS:@srcroot@%.c=@objroot@%)
|
||||
|
||||
@@ -164,12 +212,14 @@ check: tests
|
||||
|
||||
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)
|
||||
rm -f $(DSOS) $(STATIC_LIBS)
|
||||
|
||||
distclean: clean
|
||||
rm -rf @objroot@autom4te.cache
|
||||
@@ -182,6 +232,8 @@ distclean: clean
|
||||
relclean: distclean
|
||||
rm -f @objroot@configure
|
||||
rm -f @srcroot@VERSION
|
||||
rm -f $(DOCS_HTML)
|
||||
rm -f $(DOCS_MAN3)
|
||||
|
||||
#===============================================================================
|
||||
# Re-configuration rules.
|
||||
|
||||
@@ -72,7 +72,7 @@ use strict;
|
||||
use warnings;
|
||||
use Getopt::Long;
|
||||
|
||||
my $PPROF_VERSION = "1.5";
|
||||
my $PPROF_VERSION = "1.7";
|
||||
|
||||
# These are the object tools we use which can come from a
|
||||
# user-specified location using --tools, from the PPROF_TOOLS
|
||||
@@ -89,6 +89,7 @@ my %obj_tool_map = (
|
||||
);
|
||||
my $DOT = "dot"; # leave non-absolute, since it may be in /usr/local
|
||||
my $GV = "gv";
|
||||
my $EVINCE = "evince"; # could also be xpdf or perhaps acroread
|
||||
my $KCACHEGRIND = "kcachegrind";
|
||||
my $PS2PDF = "ps2pdf";
|
||||
# These are used for dynamic profiles
|
||||
@@ -103,6 +104,7 @@ my $GROWTH_PAGE = "/pprof/growth";
|
||||
my $CONTENTION_PAGE = "/pprof/contention";
|
||||
my $WALL_PAGE = "/pprof/wall(?:\\?.*)?"; # accepts options like namefilter
|
||||
my $FILTEREDPROFILE_PAGE = "/pprof/filteredprofile(?:\\?.*)?";
|
||||
my $CENSUSPROFILE_PAGE = "/pprof/censusprofile"; # must support "?seconds=#"
|
||||
my $SYMBOL_PAGE = "/pprof/symbol"; # must support symbol lookup via POST
|
||||
my $PROGRAM_NAME_PAGE = "/pprof/cmdline";
|
||||
|
||||
@@ -110,7 +112,7 @@ my $PROGRAM_NAME_PAGE = "/pprof/cmdline";
|
||||
# All the alternatives must begin with /.
|
||||
my $PROFILES = "($HEAP_PAGE|$PROFILE_PAGE|$PMUPROFILE_PAGE|" .
|
||||
"$GROWTH_PAGE|$CONTENTION_PAGE|$WALL_PAGE|" .
|
||||
"$FILTEREDPROFILE_PAGE)";
|
||||
"$FILTEREDPROFILE_PAGE|$CENSUSPROFILE_PAGE)";
|
||||
|
||||
# default binary name
|
||||
my $UNKNOWN_BINARY = "(unknown)";
|
||||
@@ -148,7 +150,7 @@ pprof [options] <profile>
|
||||
|
||||
The /<service> can be $HEAP_PAGE, $PROFILE_PAGE, /pprof/pmuprofile,
|
||||
$GROWTH_PAGE, $CONTENTION_PAGE, /pprof/wall,
|
||||
or /pprof/filteredprofile.
|
||||
$CENSUSPROFILE_PAGE, or /pprof/filteredprofile.
|
||||
For instance: "pprof http://myserver.com:80$HEAP_PAGE".
|
||||
If /<service> is omitted, the service defaults to $PROFILE_PAGE (cpu profiling).
|
||||
pprof --symbols <program>
|
||||
@@ -180,6 +182,7 @@ Output type:
|
||||
--text Generate text report
|
||||
--callgrind Generate callgrind format to stdout
|
||||
--gv Generate Postscript and display
|
||||
--evince Generate PDF and display
|
||||
--web Generate SVG and display
|
||||
--list=<regexp> Generate source listing of matching routines
|
||||
--disasm=<regexp> Generate disassembly of matching routines
|
||||
@@ -208,6 +211,7 @@ Call-graph Options:
|
||||
--nodecount=<n> Show at most so many nodes [default=80]
|
||||
--nodefraction=<f> Hide nodes below <f>*total [default=.005]
|
||||
--edgefraction=<f> Hide edges below <f>*total [default=.001]
|
||||
--maxdegree=<n> Max incoming/outgoing edges per node [default=8]
|
||||
--focus=<regexp> Focus on nodes matching <regexp>
|
||||
--ignore=<regexp> Ignore nodes matching <regexp>
|
||||
--scale=<n> Set GV scaling [default=0]
|
||||
@@ -304,6 +308,7 @@ sub Init() {
|
||||
$main::opt_disasm = "";
|
||||
$main::opt_symbols = 0;
|
||||
$main::opt_gv = 0;
|
||||
$main::opt_evince = 0;
|
||||
$main::opt_web = 0;
|
||||
$main::opt_dot = 0;
|
||||
$main::opt_ps = 0;
|
||||
@@ -315,6 +320,7 @@ sub Init() {
|
||||
$main::opt_nodecount = 80;
|
||||
$main::opt_nodefraction = 0.005;
|
||||
$main::opt_edgefraction = 0.001;
|
||||
$main::opt_maxdegree = 8;
|
||||
$main::opt_focus = '';
|
||||
$main::opt_ignore = '';
|
||||
$main::opt_scale = 0;
|
||||
@@ -372,6 +378,7 @@ sub Init() {
|
||||
"disasm=s" => \$main::opt_disasm,
|
||||
"symbols!" => \$main::opt_symbols,
|
||||
"gv!" => \$main::opt_gv,
|
||||
"evince!" => \$main::opt_evince,
|
||||
"web!" => \$main::opt_web,
|
||||
"dot!" => \$main::opt_dot,
|
||||
"ps!" => \$main::opt_ps,
|
||||
@@ -383,6 +390,7 @@ sub Init() {
|
||||
"nodecount=i" => \$main::opt_nodecount,
|
||||
"nodefraction=f" => \$main::opt_nodefraction,
|
||||
"edgefraction=f" => \$main::opt_edgefraction,
|
||||
"maxdegree=i" => \$main::opt_maxdegree,
|
||||
"focus=s" => \$main::opt_focus,
|
||||
"ignore=s" => \$main::opt_ignore,
|
||||
"scale=i" => \$main::opt_scale,
|
||||
@@ -452,6 +460,7 @@ sub Init() {
|
||||
($main::opt_disasm eq '' ? 0 : 1) +
|
||||
($main::opt_symbols == 0 ? 0 : 1) +
|
||||
$main::opt_gv +
|
||||
$main::opt_evince +
|
||||
$main::opt_web +
|
||||
$main::opt_dot +
|
||||
$main::opt_ps +
|
||||
@@ -646,6 +655,8 @@ sub Main() {
|
||||
if (PrintDot($main::prog, $symbols, $profile, $flat, $cumulative, $total)) {
|
||||
if ($main::opt_gv) {
|
||||
RunGV(TempName($main::next_tmpfile, "ps"), "");
|
||||
} elsif ($main::opt_evince) {
|
||||
RunEvince(TempName($main::next_tmpfile, "pdf"), "");
|
||||
} elsif ($main::opt_web) {
|
||||
my $tmp = TempName($main::next_tmpfile, "svg");
|
||||
RunWeb($tmp);
|
||||
@@ -708,6 +719,12 @@ sub RunGV {
|
||||
}
|
||||
}
|
||||
|
||||
sub RunEvince {
|
||||
my $fname = shift;
|
||||
my $bg = shift; # "" or " &" if we should run in background
|
||||
system("$EVINCE " . $fname . $bg);
|
||||
}
|
||||
|
||||
sub RunWeb {
|
||||
my $fname = shift;
|
||||
print STDERR "Loading web page file:///$fname\n";
|
||||
@@ -805,6 +822,7 @@ sub InteractiveCommand {
|
||||
$main::opt_disasm = 0;
|
||||
$main::opt_list = 0;
|
||||
$main::opt_gv = 0;
|
||||
$main::opt_evince = 0;
|
||||
$main::opt_cum = 0;
|
||||
|
||||
if (m/^\s*(text|top)(\d*)\s*(.*)/) {
|
||||
@@ -878,11 +896,14 @@ sub InteractiveCommand {
|
||||
PrintDisassembly($libs, $flat, $cumulative, $routine, $total);
|
||||
return 1;
|
||||
}
|
||||
if (m/^\s*(gv|web)\s*(.*)/) {
|
||||
if (m/^\s*(gv|web|evince)\s*(.*)/) {
|
||||
$main::opt_gv = 0;
|
||||
$main::opt_evince = 0;
|
||||
$main::opt_web = 0;
|
||||
if ($1 eq "gv") {
|
||||
$main::opt_gv = 1;
|
||||
} elsif ($1 eq "evince") {
|
||||
$main::opt_evince = 1;
|
||||
} elsif ($1 eq "web") {
|
||||
$main::opt_web = 1;
|
||||
}
|
||||
@@ -902,6 +923,8 @@ sub InteractiveCommand {
|
||||
if (PrintDot($main::prog, $symbols, $profile, $flat, $cumulative, $total)) {
|
||||
if ($main::opt_gv) {
|
||||
RunGV(TempName($main::next_tmpfile, "ps"), " &");
|
||||
} elsif ($main::opt_evince) {
|
||||
RunEvince(TempName($main::next_tmpfile, "pdf"), " &");
|
||||
} elsif ($main::opt_web) {
|
||||
RunWeb(TempName($main::next_tmpfile, "svg"));
|
||||
}
|
||||
@@ -1685,6 +1708,8 @@ sub PrintDot {
|
||||
my $output;
|
||||
if ($main::opt_gv) {
|
||||
$output = "| $DOT -Tps2 >" . TempName($main::next_tmpfile, "ps");
|
||||
} elsif ($main::opt_evince) {
|
||||
$output = "| $DOT -Tps2 | $PS2PDF - " . TempName($main::next_tmpfile, "pdf");
|
||||
} elsif ($main::opt_ps) {
|
||||
$output = "| $DOT -Tps2";
|
||||
} elsif ($main::opt_pdf) {
|
||||
@@ -1792,12 +1817,38 @@ sub PrintDot {
|
||||
}
|
||||
}
|
||||
|
||||
# Print edges
|
||||
foreach my $e (keys(%edge)) {
|
||||
# Print edges (process in order of decreasing counts)
|
||||
my %indegree = (); # Number of incoming edges added per node so far
|
||||
my %outdegree = (); # Number of outgoing edges added per node so far
|
||||
foreach my $e (sort { $edge{$b} <=> $edge{$a} } keys(%edge)) {
|
||||
my @x = split(/\001/, $e);
|
||||
$n = $edge{$e};
|
||||
|
||||
if (abs($n) > $edgelimit) {
|
||||
# Initialize degree of kept incoming and outgoing edges if necessary
|
||||
my $src = $x[0];
|
||||
my $dst = $x[1];
|
||||
if (!exists($outdegree{$src})) { $outdegree{$src} = 0; }
|
||||
if (!exists($indegree{$dst})) { $indegree{$dst} = 0; }
|
||||
|
||||
my $keep;
|
||||
if ($indegree{$dst} == 0) {
|
||||
# Keep edge if needed for reachability
|
||||
$keep = 1;
|
||||
} elsif (abs($n) <= $edgelimit) {
|
||||
# Drop if we are below --edgefraction
|
||||
$keep = 0;
|
||||
} elsif ($outdegree{$src} >= $main::opt_maxdegree ||
|
||||
$indegree{$dst} >= $main::opt_maxdegree) {
|
||||
# Keep limited number of in/out edges per node
|
||||
$keep = 0;
|
||||
} else {
|
||||
$keep = 1;
|
||||
}
|
||||
|
||||
if ($keep) {
|
||||
$outdegree{$src}++;
|
||||
$indegree{$dst}++;
|
||||
|
||||
# Compute line width based on edge count
|
||||
my $fraction = abs($local_total ? (3 * ($n / $local_total)) : 0);
|
||||
if ($fraction > 1) { $fraction = 1; }
|
||||
@@ -2135,6 +2186,19 @@ function handleMouseUp(evt) {
|
||||
EOF
|
||||
}
|
||||
|
||||
# Return a small number that identifies the argument.
|
||||
# Multiple calls with the same argument will return the same number.
|
||||
# Calls with different arguments will return different numbers.
|
||||
sub ShortIdFor {
|
||||
my $key = shift;
|
||||
my $id = $main::uniqueid{$key};
|
||||
if (!defined($id)) {
|
||||
$id = keys(%main::uniqueid) + 1;
|
||||
$main::uniqueid{$key} = $id;
|
||||
}
|
||||
return $id;
|
||||
}
|
||||
|
||||
# Translate a stack of addresses into a stack of symbols
|
||||
sub TranslateStack {
|
||||
my $symbols = shift;
|
||||
@@ -2172,6 +2236,15 @@ sub TranslateStack {
|
||||
if ($j > 2) {
|
||||
$func = "$func (inline)";
|
||||
}
|
||||
|
||||
# Do not merge nodes corresponding to Callback::Run since that
|
||||
# causes confusing cycles in dot display. Instead, we synthesize
|
||||
# a unique name for this frame per caller.
|
||||
if ($func =~ m/Callback.*::Run$/) {
|
||||
my $caller = ($i > 0) ? $addrs[$i-1] : 0;
|
||||
$func = "Run#" . ShortIdFor($caller);
|
||||
}
|
||||
|
||||
if ($main::opt_addresses) {
|
||||
push(@result, "$a $func $fileline");
|
||||
} elsif ($main::opt_lines) {
|
||||
@@ -2415,7 +2488,16 @@ sub RemoveUninterestingFrames {
|
||||
# old code out of the system.
|
||||
$skip_regexp = "TCMalloc|^tcmalloc::";
|
||||
} elsif ($main::profile_type eq 'contention') {
|
||||
foreach my $vname ('Mutex::Unlock', 'Mutex::UnlockSlow') {
|
||||
foreach my $vname ('base::RecordLockProfileData',
|
||||
'base::SubmitMutexProfileData',
|
||||
'base::SubmitSpinLockProfileData',
|
||||
'Mutex::Unlock',
|
||||
'Mutex::UnlockSlow',
|
||||
'Mutex::ReaderUnlock',
|
||||
'MutexLock::~MutexLock',
|
||||
'SpinLock::Unlock',
|
||||
'SpinLock::SlowUnlock',
|
||||
'SpinLockHolder::~SpinLockHolder') {
|
||||
$skip{$vname} = 1;
|
||||
}
|
||||
} elsif ($main::profile_type eq 'cpu') {
|
||||
@@ -2955,7 +3037,7 @@ sub FetchDynamicProfile {
|
||||
|
||||
my $fetcher = AddFetchTimeout($URL_FETCHER, $fetch_timeout);
|
||||
my $cmd = "$fetcher '$url' > '$tmp_profile'";
|
||||
if ($path =~ m/$PROFILE_PAGE|$PMUPROFILE_PAGE/){
|
||||
if ($path =~ m/$PROFILE_PAGE|$PMUPROFILE_PAGE|$CENSUSPROFILE_PAGE/){
|
||||
print STDERR "Gathering CPU profile from $url for $main::opt_seconds seconds to\n ${real_profile}\n";
|
||||
if ($encourage_patience) {
|
||||
print STDERR "Be patient...\n";
|
||||
@@ -3154,24 +3236,47 @@ BEGIN {
|
||||
}
|
||||
}
|
||||
|
||||
# Return the next line from the profile file, assuming it's a text
|
||||
# line (which in this case means, doesn't start with a NUL byte). If
|
||||
# it's not a text line, return "". At EOF, return undef, like perl does.
|
||||
# Input file should be in binmode.
|
||||
sub ReadProfileLine {
|
||||
# Reads the top, 'header' section of a profile, and returns the last
|
||||
# line of the header, commonly called a 'header line'. The header
|
||||
# section of a profile consists of zero or more 'command' lines that
|
||||
# are instructions to pprof, which pprof executes when reading the
|
||||
# header. All 'command' lines start with a %. After the command
|
||||
# lines is the 'header line', which is a profile-specific line that
|
||||
# indicates what type of profile it is, and perhaps other global
|
||||
# information about the profile. For instance, here's a header line
|
||||
# for a heap profile:
|
||||
# heap profile: 53: 38236 [ 5525: 1284029] @ heapprofile
|
||||
# For historical reasons, the CPU profile does not contain a text-
|
||||
# readable header line. If the profile looks like a CPU profile,
|
||||
# this function returns "". If no header line could be found, this
|
||||
# function returns undef.
|
||||
#
|
||||
# The following commands are recognized:
|
||||
# %warn -- emit the rest of this line to stderr, prefixed by 'WARNING:'
|
||||
#
|
||||
# The input file should be in binmode.
|
||||
sub ReadProfileHeader {
|
||||
local *PROFILE = shift;
|
||||
my $firstchar = "";
|
||||
my $line = "";
|
||||
read(PROFILE, $firstchar, 1);
|
||||
seek(PROFILE, -1, 1); # unread the firstchar
|
||||
if ($firstchar eq "\0") {
|
||||
seek(PROFILE, -1, 1); # unread the firstchar
|
||||
if ($firstchar !~ /[[:print:]]/) { # is not a text character
|
||||
return "";
|
||||
}
|
||||
$line = <PROFILE>;
|
||||
if (defined($line)) {
|
||||
while (defined($line = <PROFILE>)) {
|
||||
$line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
|
||||
if ($line =~ /^%warn\s+(.*)/) { # 'warn' command
|
||||
# Note this matches both '%warn blah\n' and '%warn\n'.
|
||||
print STDERR "WARNING: $1\n"; # print the rest of the line
|
||||
} elsif ($line =~ /^%/) {
|
||||
print STDERR "Ignoring unknown command from profile header: $line";
|
||||
} else {
|
||||
# End of commands, must be the header line.
|
||||
return $line;
|
||||
}
|
||||
}
|
||||
return $line;
|
||||
return undef; # got to EOF without seeing a header line
|
||||
}
|
||||
|
||||
sub IsSymbolizedProfileFile {
|
||||
@@ -3182,7 +3287,7 @@ sub IsSymbolizedProfileFile {
|
||||
# Check if the file contains a symbol-section marker.
|
||||
open(TFILE, "<$file_name");
|
||||
binmode TFILE;
|
||||
my $firstline = ReadProfileLine(*TFILE);
|
||||
my $firstline = ReadProfileHeader(*TFILE);
|
||||
close(TFILE);
|
||||
if (!$firstline) {
|
||||
return 0;
|
||||
@@ -3202,14 +3307,7 @@ sub IsSymbolizedProfileFile {
|
||||
sub ReadProfile {
|
||||
my $prog = shift;
|
||||
my $fname = shift;
|
||||
|
||||
if (IsSymbolizedProfileFile($fname) && !$main::use_symbolized_profile) {
|
||||
# we have both a binary and symbolized profiles, abort
|
||||
usage("Symbolized profile '$fname' cannot be used with a binary arg. " .
|
||||
"Try again without passing '$prog'.");
|
||||
}
|
||||
|
||||
$main::profile_type = '';
|
||||
my $result; # return value
|
||||
|
||||
$CONTENTION_PAGE =~ m,[^/]+$,; # matches everything after the last slash
|
||||
my $contention_marker = $&;
|
||||
@@ -3226,40 +3324,45 @@ sub ReadProfile {
|
||||
# whole firstline, since it may be gigabytes(!) of data.
|
||||
open(PROFILE, "<$fname") || error("$fname: $!\n");
|
||||
binmode PROFILE; # New perls do UTF-8 processing
|
||||
my $header = ReadProfileLine(*PROFILE);
|
||||
my $header = ReadProfileHeader(*PROFILE);
|
||||
if (!defined($header)) { # means "at EOF"
|
||||
error("Profile is empty.\n");
|
||||
}
|
||||
|
||||
my $symbols;
|
||||
if ($header =~ m/^--- *$symbol_marker/o) {
|
||||
# Verify that the user asked for a symbolized profile
|
||||
if (!$main::use_symbolized_profile) {
|
||||
# we have both a binary and symbolized profiles, abort
|
||||
error("FATAL ERROR: Symbolized profile\n $fname\ncannot be used with " .
|
||||
"a binary arg. Try again without passing\n $prog\n");
|
||||
}
|
||||
# Read the symbol section of the symbolized profile file.
|
||||
$symbols = ReadSymbols(*PROFILE{IO});
|
||||
# Read the next line to get the header for the remaining profile.
|
||||
$header = ReadProfileLine(*PROFILE) || "";
|
||||
$header = ReadProfileHeader(*PROFILE) || "";
|
||||
}
|
||||
|
||||
my $result;
|
||||
|
||||
$main::profile_type = '';
|
||||
if ($header =~ m/^heap profile:.*$growth_marker/o) {
|
||||
$main::profile_type = 'growth';
|
||||
$result = ReadHeapProfile($prog, $fname, $header);
|
||||
$result = ReadHeapProfile($prog, *PROFILE, $header);
|
||||
} elsif ($header =~ m/^heap profile:/) {
|
||||
$main::profile_type = 'heap';
|
||||
$result = ReadHeapProfile($prog, $fname, $header);
|
||||
$result = ReadHeapProfile($prog, *PROFILE, $header);
|
||||
} elsif ($header =~ m/^--- *$contention_marker/o) {
|
||||
$main::profile_type = 'contention';
|
||||
$result = ReadSynchProfile($prog, $fname);
|
||||
$result = ReadSynchProfile($prog, *PROFILE);
|
||||
} elsif ($header =~ m/^--- *Stacks:/) {
|
||||
print STDERR
|
||||
"Old format contention profile: mistakenly reports " .
|
||||
"condition variable signals as lock contentions.\n";
|
||||
$main::profile_type = 'contention';
|
||||
$result = ReadSynchProfile($prog, $fname);
|
||||
$result = ReadSynchProfile($prog, *PROFILE);
|
||||
} elsif ($header =~ m/^--- *$profile_marker/) {
|
||||
# the binary cpu profile data starts immediately after this line
|
||||
$main::profile_type = 'cpu';
|
||||
$result = ReadCPUProfile($prog, $fname);
|
||||
$result = ReadCPUProfile($prog, $fname, *PROFILE);
|
||||
} else {
|
||||
if (defined($symbols)) {
|
||||
# a symbolized profile contains a format we don't recognize, bail out
|
||||
@@ -3267,9 +3370,11 @@ sub ReadProfile {
|
||||
}
|
||||
# no ascii header present -- must be a CPU profile
|
||||
$main::profile_type = 'cpu';
|
||||
$result = ReadCPUProfile($prog, $fname);
|
||||
$result = ReadCPUProfile($prog, $fname, *PROFILE);
|
||||
}
|
||||
|
||||
close(PROFILE);
|
||||
|
||||
# if we got symbols along with the profile, return those as well
|
||||
if (defined($symbols)) {
|
||||
$result->{symbols} = $symbols;
|
||||
@@ -3308,7 +3413,8 @@ sub FixCallerAddresses {
|
||||
# CPU profile reader
|
||||
sub ReadCPUProfile {
|
||||
my $prog = shift;
|
||||
my $fname = shift;
|
||||
my $fname = shift; # just used for logging
|
||||
local *PROFILE = shift;
|
||||
my $version;
|
||||
my $period;
|
||||
my $i;
|
||||
@@ -3375,7 +3481,6 @@ sub ReadCPUProfile {
|
||||
my $map = '';
|
||||
seek(PROFILE, $i * 4, 0);
|
||||
read(PROFILE, $map, (stat PROFILE)[7]);
|
||||
close(PROFILE);
|
||||
|
||||
my $r = {};
|
||||
$r->{version} = $version;
|
||||
@@ -3389,7 +3494,7 @@ sub ReadCPUProfile {
|
||||
|
||||
sub ReadHeapProfile {
|
||||
my $prog = shift;
|
||||
my $fname = shift;
|
||||
local *PROFILE = shift;
|
||||
my $header = shift;
|
||||
|
||||
my $index = 1;
|
||||
@@ -3534,14 +3639,14 @@ sub ReadHeapProfile {
|
||||
if ($n1 != 0) {
|
||||
my $ratio = (($s1*1.0)/$n1)/($sample_adjustment);
|
||||
my $scale_factor = 1/(1 - exp(-$ratio));
|
||||
$n1 *= $scale_factor;
|
||||
$s1 *= $scale_factor;
|
||||
$n1 *= $scale_factor;
|
||||
$s1 *= $scale_factor;
|
||||
}
|
||||
if ($n2 != 0) {
|
||||
my $ratio = (($s2*1.0)/$n2)/($sample_adjustment);
|
||||
my $scale_factor = 1/(1 - exp(-$ratio));
|
||||
$n2 *= $scale_factor;
|
||||
$s2 *= $scale_factor;
|
||||
$n2 *= $scale_factor;
|
||||
$s2 *= $scale_factor;
|
||||
}
|
||||
} else {
|
||||
# Remote-heap version 1
|
||||
@@ -3574,7 +3679,9 @@ sub ReadHeapProfile {
|
||||
}
|
||||
|
||||
sub ReadSynchProfile {
|
||||
my ($prog, $fname, $header) = @_;
|
||||
my $prog = shift;
|
||||
local *PROFILE = shift;
|
||||
my $header = shift;
|
||||
|
||||
my $map = '';
|
||||
my $profile = {};
|
||||
@@ -3649,7 +3756,6 @@ sub ReadSynchProfile {
|
||||
$map .= $line;
|
||||
}
|
||||
}
|
||||
close PROFILE;
|
||||
|
||||
if (!$seen_clockrate) {
|
||||
printf STDERR ("No cycles/second entry in profile; Guessing %.1f GHz\n",
|
||||
@@ -4098,8 +4204,9 @@ sub ExtractSymbols {
|
||||
# advance through the libraries as we advance the pc. Sometimes the
|
||||
# addresses of libraries may overlap with the addresses of the main
|
||||
# binary, so to make sure the libraries 'win', we iterate over the
|
||||
# libraries in reverse order (binary will have the lowest start addr).
|
||||
my @pcs = (sort { $a cmp $b } keys(%{$pcset}));
|
||||
# libraries in reverse order (which assumes the binary doesn't start
|
||||
# in the middle of a library, which seems a fair assumption).
|
||||
my @pcs = (sort { $a cmp $b } keys(%{$pcset})); # pcset is 0-extended strings
|
||||
foreach my $lib (sort {$b->[1] cmp $a->[1]} @{$libs}) {
|
||||
my $libname = $lib->[0];
|
||||
my $start = $lib->[1];
|
||||
@@ -4109,14 +4216,18 @@ sub ExtractSymbols {
|
||||
# Get list of pcs that belong in this library.
|
||||
my $contained = [];
|
||||
my ($start_pc_index, $finish_pc_index);
|
||||
# Find smallest finish_pc_index such that $finish < $pc[$finish_pc_index].
|
||||
for ($finish_pc_index = $#pcs + 1; $finish_pc_index > 0;
|
||||
$finish_pc_index--) {
|
||||
last if $pcs[$finish_pc_index - 1] le $finish;
|
||||
}
|
||||
# Find smallest start_pc_index such that $start <= $pc[$start_pc_index].
|
||||
for ($start_pc_index = $finish_pc_index; $start_pc_index > 0;
|
||||
$start_pc_index--) {
|
||||
last if $pcs[$start_pc_index - 1] lt $start;
|
||||
}
|
||||
# This keeps PC values higher than $pc[$finish_pc_index] in @pcs,
|
||||
# in case there are overlaps in libraries and the main binary.
|
||||
@{$contained} = splice(@pcs, $start_pc_index,
|
||||
$finish_pc_index - $start_pc_index);
|
||||
# Map to symbols
|
||||
|
||||
@@ -80,6 +80,19 @@ MANDIR=`eval echo $mandir`
|
||||
MANDIR=`eval echo $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 just prevent autoconf from molesting CFLAGS.
|
||||
CFLAGS=$CFLAGS
|
||||
@@ -119,6 +132,16 @@ else
|
||||
fi
|
||||
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
|
||||
dnl CPU-specific settings.
|
||||
CPU_SPINWAIT=""
|
||||
@@ -144,17 +167,6 @@ case "${host_cpu}" in
|
||||
esac
|
||||
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" -a "${abi}" = "xelf"; then
|
||||
JE_CFLAGS_APPEND([-fvisibility=internal])
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl Platform-specific settings. abi and RPATH can probably be determined
|
||||
dnl programmatically, but doing so is error-prone, which makes it generally
|
||||
dnl not worth the trouble.
|
||||
@@ -214,6 +226,27 @@ esac
|
||||
AC_SUBST([abi])
|
||||
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.
|
||||
AC_ARG_WITH([rpath],
|
||||
[AS_HELP_STRING([--with-rpath=<rpath>], [Colon-separated rpath (ELF systems only)])],
|
||||
@@ -275,17 +308,26 @@ AC_ARG_WITH([install_suffix],
|
||||
install_suffix="$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/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/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/internal/jemalloc_internal.h"
|
||||
cfgoutputs_tup="${cfgoutputs_tup} test/jemalloc_test.h:test/jemalloc_test.h.in"
|
||||
@@ -329,15 +371,6 @@ if test "x$enable_debug" = "x1" ; then
|
||||
AC_DEFINE([JEMALLOC_IVSALLOC], [ ])
|
||||
fi
|
||||
AC_SUBST([enable_debug])
|
||||
if test "x$enable_debug" = "x0" ; then
|
||||
roff_debug=".\\\" "
|
||||
roff_no_debug=""
|
||||
else
|
||||
roff_debug=""
|
||||
roff_no_debug=".\\\" "
|
||||
fi
|
||||
AC_SUBST([roff_debug])
|
||||
AC_SUBST([roff_no_debug])
|
||||
|
||||
dnl Only optimize if not debugging.
|
||||
if test "x$enable_debug" = "x0" -a "x$no_CFLAGS" = "xyes" ; then
|
||||
@@ -369,12 +402,6 @@ if test "x$enable_stats" = "x1" ; then
|
||||
AC_DEFINE([JEMALLOC_STATS], [ ])
|
||||
fi
|
||||
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.
|
||||
AC_ARG_ENABLE([prof],
|
||||
@@ -387,17 +414,12 @@ fi
|
||||
],
|
||||
[enable_prof="0"]
|
||||
)
|
||||
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"
|
||||
if test "x$enable_prof" = "x1" ; then
|
||||
backtrace_method=""
|
||||
else
|
||||
enable_prof_libgcc="1"
|
||||
backtrace_method="N/A"
|
||||
fi
|
||||
],
|
||||
[enable_prof_libgcc="1"]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE([prof-libunwind],
|
||||
[AS_HELP_STRING([--enable-prof-libunwind], [Use libunwind for backtracing])],
|
||||
[if test "x$enable_prof_libunwind" = "xno" ; then
|
||||
@@ -421,47 +443,89 @@ else
|
||||
fi,
|
||||
LUNWIND="-lunwind"
|
||||
)
|
||||
if test "x$backtrace_method" = "x" -a "x$enable_prof_libunwind" = "x1" ; then
|
||||
AC_CHECK_HEADERS([libunwind.h], , [enable_prof_libunwind="0"])
|
||||
if test "x$LUNWIND" = "x-lunwind" ; then
|
||||
AC_CHECK_LIB([unwind], [backtrace], [LIBS="$LIBS $LUNWIND"],
|
||||
[enable_prof_libunwind="0"])
|
||||
else
|
||||
LIBS="$LIBS $LUNWIND"
|
||||
fi
|
||||
if test "x${enable_prof_libunwind}" = "x1" ; then
|
||||
backtrace_method="libunwind"
|
||||
AC_DEFINE([JEMALLOC_PROF_LIBUNWIND], [ ])
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE([prof-libgcc],
|
||||
[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], [ ])
|
||||
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 for backtracing.
|
||||
if test "x$enable_prof" = "x1" -a "x$enable_prof_libgcc" = "x1" ; then
|
||||
if test "x$enable_prof_libunwind" = "x0" -a "x$GCC" = "xyes" ; then
|
||||
enable_prof_libgcc="1"
|
||||
AC_CHECK_HEADERS([unwind.h], , [enable_prof_libgcc="0"])
|
||||
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], [ ])
|
||||
fi
|
||||
else
|
||||
enable_prof_libgcc="0"
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl Enable tiny allocations by default.
|
||||
AC_ARG_ENABLE([tiny],
|
||||
@@ -478,15 +542,6 @@ if test "x$enable_tiny" = "x1" ; then
|
||||
AC_DEFINE([JEMALLOC_TINY], [ ])
|
||||
fi
|
||||
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.
|
||||
AC_ARG_ENABLE([tcache],
|
||||
@@ -503,15 +558,6 @@ 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 Do not enable mmap()ped swap files by default.
|
||||
AC_ARG_ENABLE([swap],
|
||||
@@ -528,12 +574,6 @@ if test "x$enable_swap" = "x1" ; then
|
||||
AC_DEFINE([JEMALLOC_SWAP], [ ])
|
||||
fi
|
||||
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.
|
||||
AC_ARG_ENABLE([dss],
|
||||
@@ -550,12 +590,6 @@ if test "x$enable_dss" = "x1" ; then
|
||||
AC_DEFINE([JEMALLOC_DSS], [ ])
|
||||
fi
|
||||
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.
|
||||
AC_ARG_ENABLE([fill],
|
||||
@@ -572,12 +606,6 @@ if test "x$enable_fill" = "x1" ; then
|
||||
AC_DEFINE([JEMALLOC_FILL], [ ])
|
||||
fi
|
||||
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.
|
||||
AC_ARG_ENABLE([xmalloc],
|
||||
@@ -594,12 +622,6 @@ if test "x$enable_xmalloc" = "x1" ; then
|
||||
AC_DEFINE([JEMALLOC_XMALLOC], [ ])
|
||||
fi
|
||||
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.
|
||||
AC_ARG_ENABLE([sysv],
|
||||
@@ -616,12 +638,6 @@ if test "x$enable_sysv" = "x1" ; then
|
||||
AC_DEFINE([JEMALLOC_SYSV], [ ])
|
||||
fi
|
||||
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.
|
||||
AC_ARG_ENABLE([dynamic_page_shift],
|
||||
@@ -746,6 +762,51 @@ if test "x${enable_tls}" = "x0" ; then
|
||||
AC_DEFINE_UNQUOTED([NO_TLS], [ ])
|
||||
fi
|
||||
|
||||
dnl ============================================================================
|
||||
dnl Check for ffsl(3), and fail if not found. This function exists on all
|
||||
dnl platforms that jemalloc currently has a chance of functioning on without
|
||||
dnl modification.
|
||||
|
||||
AC_CHECK_FUNC([ffsl], [],
|
||||
[AC_MSG_ERROR([Cannot build without ffsl(3)])])
|
||||
|
||||
dnl ============================================================================
|
||||
dnl Check for atomic(3) operations as provided on Darwin.
|
||||
|
||||
JE_COMPILABLE([Darwin OSAtomic*()], [
|
||||
#include <libkern/OSAtomic.h>
|
||||
#include <inttypes.h>
|
||||
], [
|
||||
{
|
||||
int32_t x32 = 0;
|
||||
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.
|
||||
|
||||
@@ -828,6 +889,9 @@ AC_MSG_RESULT([LDFLAGS : ${LDFLAGS}])
|
||||
AC_MSG_RESULT([LIBS : ${LIBS}])
|
||||
AC_MSG_RESULT([RPATH_EXTRA : ${RPATH_EXTRA}])
|
||||
AC_MSG_RESULT([])
|
||||
AC_MSG_RESULT([XSLTPROC : ${XSLTPROC}])
|
||||
AC_MSG_RESULT([XSLROOT : ${XSLROOT}])
|
||||
AC_MSG_RESULT([])
|
||||
AC_MSG_RESULT([PREFIX : ${PREFIX}])
|
||||
AC_MSG_RESULT([BINDIR : ${BINDIR}])
|
||||
AC_MSG_RESULT([INCLUDEDIR : ${INCLUDEDIR}])
|
||||
@@ -847,8 +911,9 @@ AC_MSG_RESULT([cc-silence : ${enable_cc_silence}])
|
||||
AC_MSG_RESULT([debug : ${enable_debug}])
|
||||
AC_MSG_RESULT([stats : ${enable_stats}])
|
||||
AC_MSG_RESULT([prof : ${enable_prof}])
|
||||
AC_MSG_RESULT([prof-libgcc : ${enable_prof_libgcc}])
|
||||
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([tcache : ${enable_tcache}])
|
||||
AC_MSG_RESULT([fill : ${enable_fill}])
|
||||
|
||||
4
jemalloc/doc/html.xsl.in
Normal file
4
jemalloc/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>
|
||||
File diff suppressed because it is too large
Load Diff
2280
jemalloc/doc/jemalloc.xml.in
Normal file
2280
jemalloc/doc/jemalloc.xml.in
Normal file
File diff suppressed because it is too large
Load Diff
4
jemalloc/doc/manpages.xsl.in
Normal file
4
jemalloc/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
jemalloc/doc/stylesheet.xsl
Normal file
7
jemalloc/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
|
||||
/* Smallest size class to support. */
|
||||
# define LG_TINY_MIN LG_SIZEOF_PTR
|
||||
# define TINY_MIN (1U << LG_TINY_MIN)
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -45,9 +46,10 @@
|
||||
* point is implicitly RUN_BFP bits to the left.
|
||||
*
|
||||
* Note that it is possible to set RUN_MAX_OVRHD low enough that it cannot be
|
||||
* honored for some/all object sizes, since there is one bit of header overhead
|
||||
* per object (plus a constant). This constraint is relaxed (ignored) for runs
|
||||
* that are so small that the per-region overhead is greater than:
|
||||
* honored for some/all object sizes, since when heap profiling is enabled
|
||||
* there is one pointer of header overhead per object (plus a constant). This
|
||||
* constraint is relaxed (ignored) for runs that are so small that the
|
||||
* per-region overhead is greater than:
|
||||
*
|
||||
* (RUN_MAX_OVRHD / (reg_size << (3+RUN_BFP))
|
||||
*/
|
||||
@@ -56,6 +58,10 @@
|
||||
#define RUN_MAX_OVRHD 0x0000003dU
|
||||
#define RUN_MAX_OVRHD_RELAX 0x00001800U
|
||||
|
||||
/* Maximum number of regions in one run. */
|
||||
#define LG_RUN_MAXREGS 11
|
||||
#define RUN_MAXREGS (1U << LG_RUN_MAXREGS)
|
||||
|
||||
/*
|
||||
* The minimum ratio of active:dirty pages per arena is computed as:
|
||||
*
|
||||
@@ -69,6 +75,7 @@
|
||||
typedef struct arena_chunk_map_s arena_chunk_map_t;
|
||||
typedef struct arena_chunk_s arena_chunk_t;
|
||||
typedef struct arena_run_s arena_run_t;
|
||||
typedef struct arena_bin_info_s arena_bin_info_t;
|
||||
typedef struct arena_bin_s arena_bin_t;
|
||||
typedef struct arena_s arena_t;
|
||||
|
||||
@@ -105,7 +112,7 @@ struct arena_chunk_map_s {
|
||||
* Run address (or size) and various flags are stored together. The bit
|
||||
* layout looks like (assuming 32-bit system):
|
||||
*
|
||||
* ???????? ???????? ????---- ----dzla
|
||||
* ???????? ???????? ????---- ----dula
|
||||
*
|
||||
* ? : Unallocated: Run address for first/last pages, unset for internal
|
||||
* pages.
|
||||
@@ -113,7 +120,7 @@ struct arena_chunk_map_s {
|
||||
* Large: Run size for first page, unset for trailing pages.
|
||||
* - : Unused.
|
||||
* d : dirty?
|
||||
* z : zeroed?
|
||||
* u : unzeroed?
|
||||
* l : large?
|
||||
* a : allocated?
|
||||
*
|
||||
@@ -129,30 +136,30 @@ struct arena_chunk_map_s {
|
||||
* [dula] : bit unset
|
||||
*
|
||||
* Unallocated (clean):
|
||||
* ssssssss ssssssss ssss---- ----du--
|
||||
* ssssssss ssssssss ssss---- ----du-a
|
||||
* xxxxxxxx xxxxxxxx xxxx---- -----Uxx
|
||||
* ssssssss ssssssss ssss---- ----dU--
|
||||
* ssssssss ssssssss ssss---- ----dU-a
|
||||
*
|
||||
* Unallocated (dirty):
|
||||
* ssssssss ssssssss ssss---- ----D---
|
||||
* ssssssss ssssssss ssss---- ----D--a
|
||||
* xxxxxxxx xxxxxxxx xxxx---- ----xxxx
|
||||
* ssssssss ssssssss ssss---- ----D---
|
||||
* ssssssss ssssssss ssss---- ----D--a
|
||||
*
|
||||
* Small:
|
||||
* pppppppp pppppppp pppp---- ----d--a
|
||||
* pppppppp pppppppp pppp---- -------a
|
||||
* pppppppp pppppppp pppp---- ----d--a
|
||||
* pppppppp pppppppp pppp---- ----d--A
|
||||
* pppppppp pppppppp pppp---- -------A
|
||||
* pppppppp pppppppp pppp---- ----d--A
|
||||
*
|
||||
* Large:
|
||||
* ssssssss ssssssss ssss---- ----D-la
|
||||
* ssssssss ssssssss ssss---- ----D-LA
|
||||
* xxxxxxxx xxxxxxxx xxxx---- ----xxxx
|
||||
* -------- -------- -------- ----D-la
|
||||
* -------- -------- -------- ----D-LA
|
||||
*
|
||||
* Large (sampled, size <= PAGE_SIZE):
|
||||
* ssssssss ssssssss sssscccc ccccD-la
|
||||
* ssssssss ssssssss sssscccc ccccD-LA
|
||||
*
|
||||
* Large (not sampled, size == PAGE_SIZE):
|
||||
* ssssssss ssssssss ssss---- ----D-la
|
||||
* ssssssss ssssssss ssss---- ----D-LA
|
||||
*/
|
||||
size_t bits;
|
||||
#ifdef JEMALLOC_PROF
|
||||
@@ -206,16 +213,52 @@ struct arena_run_s {
|
||||
/* Bin this run is associated with. */
|
||||
arena_bin_t *bin;
|
||||
|
||||
/* Stack of available freed regions, or NULL. */
|
||||
void *avail;
|
||||
|
||||
/* Next region that has never been allocated, or run boundary. */
|
||||
void *next;
|
||||
/* Index of next region that has never been allocated, or nregs. */
|
||||
uint32_t nextind;
|
||||
|
||||
/* Number of free regions in run. */
|
||||
unsigned nfree;
|
||||
};
|
||||
|
||||
/*
|
||||
* Read-only information associated with each element of arena_t's bins array
|
||||
* is stored separately, partly to reduce memory usage (only one copy, rather
|
||||
* than one per arena), but mainly to avoid false cacheline sharing.
|
||||
*/
|
||||
struct arena_bin_info_s {
|
||||
/* Size of regions in a run for this bin's size class. */
|
||||
size_t reg_size;
|
||||
|
||||
/* Total size of a run for this bin's size class. */
|
||||
size_t run_size;
|
||||
|
||||
/* Total number of regions in a run for this bin's size class. */
|
||||
uint32_t nregs;
|
||||
|
||||
/*
|
||||
* Offset of first bitmap_t element in a run header for this bin's size
|
||||
* class.
|
||||
*/
|
||||
uint32_t bitmap_offset;
|
||||
|
||||
/*
|
||||
* Metadata used to manipulate bitmaps for runs associated with this
|
||||
* bin.
|
||||
*/
|
||||
bitmap_info_t bitmap_info;
|
||||
|
||||
#ifdef JEMALLOC_PROF
|
||||
/*
|
||||
* Offset of first (prof_ctx_t *) in a run header for this bin's size
|
||||
* class, or 0 if (opt_prof == false).
|
||||
*/
|
||||
uint32_t ctx0_offset;
|
||||
#endif
|
||||
|
||||
/* Offset of first region in a run for this bin's size class. */
|
||||
uint32_t reg0_offset;
|
||||
};
|
||||
|
||||
struct arena_bin_s {
|
||||
/*
|
||||
* All operations on runcur, runs, and stats require that lock be
|
||||
@@ -240,26 +283,6 @@ struct arena_bin_s {
|
||||
*/
|
||||
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
|
||||
/* Bin statistics. */
|
||||
malloc_bin_stats_t stats;
|
||||
@@ -276,8 +299,18 @@ struct arena_s {
|
||||
unsigned ind;
|
||||
|
||||
/*
|
||||
* All non-bin-related operations on this arena require that lock be
|
||||
* locked.
|
||||
* Number of threads currently assigned to this arena. This field is
|
||||
* protected by arenas_lock.
|
||||
*/
|
||||
unsigned nthreads;
|
||||
|
||||
/*
|
||||
* There are three classes of arena operations from a locking
|
||||
* perspective:
|
||||
* 1) Thread asssignment (modifies nthreads) is protected by
|
||||
* arenas_lock.
|
||||
* 2) Bin-related operations are protected by bin locks.
|
||||
* 3) Chunk- and run-related operations are protected by this mutex.
|
||||
*/
|
||||
malloc_mutex_t lock;
|
||||
|
||||
@@ -347,45 +380,35 @@ struct arena_s {
|
||||
|
||||
/*
|
||||
* bins is used to store trees of free regions of the following sizes,
|
||||
* assuming a 16-byte quantum, 4 KiB page size, and default
|
||||
* JEMALLOC_OPTIONS.
|
||||
* assuming a 64-bit system with 16-byte quantum, 4 KiB page size, and
|
||||
* default MALLOC_CONF.
|
||||
*
|
||||
* bins[i] | size |
|
||||
* --------+--------+
|
||||
* 0 | 2 |
|
||||
* 1 | 4 |
|
||||
* 2 | 8 |
|
||||
* 0 | 8 |
|
||||
* --------+--------+
|
||||
* 3 | 16 |
|
||||
* 4 | 32 |
|
||||
* 5 | 48 |
|
||||
* 1 | 16 |
|
||||
* 2 | 32 |
|
||||
* 3 | 48 |
|
||||
* : :
|
||||
* 8 | 96 |
|
||||
* 9 | 112 |
|
||||
* 10 | 128 |
|
||||
* 6 | 96 |
|
||||
* 7 | 112 |
|
||||
* 8 | 128 |
|
||||
* --------+--------+
|
||||
* 11 | 192 |
|
||||
* 12 | 256 |
|
||||
* 13 | 320 |
|
||||
* 14 | 384 |
|
||||
* 15 | 448 |
|
||||
* 16 | 512 |
|
||||
* 9 | 192 |
|
||||
* 10 | 256 |
|
||||
* 11 | 320 |
|
||||
* 12 | 384 |
|
||||
* 13 | 448 |
|
||||
* 14 | 512 |
|
||||
* --------+--------+
|
||||
* 17 | 768 |
|
||||
* 18 | 1024 |
|
||||
* 19 | 1280 |
|
||||
* 15 | 768 |
|
||||
* 16 | 1024 |
|
||||
* 17 | 1280 |
|
||||
* : :
|
||||
* 27 | 3328 |
|
||||
* 28 | 3584 |
|
||||
* 29 | 3840 |
|
||||
* --------+--------+
|
||||
* 30 | 4 KiB |
|
||||
* 31 | 6 KiB |
|
||||
* 33 | 8 KiB |
|
||||
* : :
|
||||
* 43 | 28 KiB |
|
||||
* 44 | 30 KiB |
|
||||
* 45 | 32 KiB |
|
||||
* 25 | 3328 |
|
||||
* 26 | 3584 |
|
||||
* 27 | 3840 |
|
||||
* --------+--------+
|
||||
*/
|
||||
arena_bin_t bins[1]; /* Dynamically sized. */
|
||||
@@ -397,8 +420,16 @@ struct arena_s {
|
||||
|
||||
extern size_t opt_lg_qspace_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;
|
||||
#define SMALL_SIZE2BIN(s) (small_size2bin[(s-1) >> LG_TINY_MIN])
|
||||
|
||||
extern arena_bin_info_t *arena_bin_info;
|
||||
|
||||
/* Various bin-related settings. */
|
||||
#ifdef JEMALLOC_TINY /* Number of (2^n)-spaced tiny bins. */
|
||||
@@ -465,8 +496,9 @@ bool arena_boot(void);
|
||||
#ifdef JEMALLOC_H_INLINES
|
||||
|
||||
#ifndef JEMALLOC_ENABLE_INLINE
|
||||
unsigned arena_run_regind(arena_run_t *run, arena_bin_t *bin,
|
||||
const void *ptr, size_t size);
|
||||
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);
|
||||
@@ -475,21 +507,37 @@ void arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr);
|
||||
#endif
|
||||
|
||||
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_))
|
||||
JEMALLOC_INLINE size_t
|
||||
arena_bin_index(arena_t *arena, arena_bin_t *bin)
|
||||
{
|
||||
size_t binind = bin - arena->bins;
|
||||
assert(binind < nbins);
|
||||
return (binind);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE unsigned
|
||||
arena_run_regind(arena_run_t *run, arena_bin_t *bin, const void *ptr,
|
||||
size_t size)
|
||||
arena_run_regind(arena_run_t *run, arena_bin_info_t *bin_info, const void *ptr)
|
||||
{
|
||||
unsigned shift, diff, regind;
|
||||
size_t size;
|
||||
|
||||
assert(run->magic == ARENA_RUN_MAGIC);
|
||||
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->reg0_offset);
|
||||
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;
|
||||
@@ -512,8 +560,8 @@ arena_run_regind(arena_run_t *run, arena_bin_t *bin, const void *ptr,
|
||||
* divide by 0, and 1 and 2 are both powers of two, which are
|
||||
* handled above.
|
||||
*/
|
||||
#define SIZE_INV_SHIFT 21
|
||||
#define SIZE_INV(s) (((1U << SIZE_INV_SHIFT) / (s)) + 1)
|
||||
#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),
|
||||
@@ -533,7 +581,7 @@ arena_run_regind(arena_run_t *run, arena_bin_t *bin, const void *ptr,
|
||||
#undef SIZE_INV_SHIFT
|
||||
}
|
||||
assert(diff == regind * size);
|
||||
assert(regind < bin->nregs);
|
||||
assert(regind < bin_info->nregs);
|
||||
|
||||
return (regind);
|
||||
}
|
||||
@@ -560,13 +608,14 @@ arena_prof_ctx_get(const void *ptr)
|
||||
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_index(chunk->arena, run->bin);
|
||||
arena_bin_info_t *bin_info = &arena_bin_info[binind];
|
||||
unsigned regind;
|
||||
|
||||
assert(run->magic == ARENA_RUN_MAGIC);
|
||||
regind = arena_run_regind(run, bin, ptr, bin->reg_size);
|
||||
dassert(run->magic == ARENA_RUN_MAGIC);
|
||||
regind = arena_run_regind(run, bin_info, ptr);
|
||||
ret = *(prof_ctx_t **)((uintptr_t)run +
|
||||
bin->ctx0_offset + (regind *
|
||||
bin_info->ctx0_offset + (regind *
|
||||
sizeof(prof_ctx_t *)));
|
||||
}
|
||||
} else
|
||||
@@ -594,12 +643,16 @@ arena_prof_ctx_set(const void *ptr, prof_ctx_t *ctx)
|
||||
(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;
|
||||
|
||||
assert(run->magic == ARENA_RUN_MAGIC);
|
||||
regind = arena_run_regind(run, bin, ptr, bin->reg_size);
|
||||
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->ctx0_offset
|
||||
*((prof_ctx_t **)((uintptr_t)run + bin_info->ctx0_offset
|
||||
+ (regind * sizeof(prof_ctx_t *)))) = ctx;
|
||||
} else
|
||||
assert((uintptr_t)ctx == (uintptr_t)1U);
|
||||
@@ -615,7 +668,7 @@ arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr)
|
||||
arena_chunk_map_t *mapelm;
|
||||
|
||||
assert(arena != NULL);
|
||||
assert(arena->magic == ARENA_MAGIC);
|
||||
dassert(arena->magic == ARENA_MAGIC);
|
||||
assert(chunk->arena == arena);
|
||||
assert(ptr != NULL);
|
||||
assert(CHUNK_ADDR2BASE(ptr) != ptr);
|
||||
@@ -638,11 +691,18 @@ arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr)
|
||||
run = (arena_run_t *)((uintptr_t)chunk +
|
||||
(uintptr_t)((pageind - (mapelm->bits >>
|
||||
PAGE_SHIFT)) << PAGE_SHIFT));
|
||||
assert(run->magic == ARENA_RUN_MAGIC);
|
||||
assert(((uintptr_t)ptr - ((uintptr_t)run +
|
||||
(uintptr_t)run->bin->reg0_offset)) %
|
||||
run->bin->reg_size == 0);
|
||||
dassert(run->magic == ARENA_RUN_MAGIC);
|
||||
bin = run->bin;
|
||||
#ifdef JEMALLOC_DEBUG
|
||||
{
|
||||
size_t binind = arena_bin_index(arena, bin);
|
||||
arena_bin_info_t *bin_info =
|
||||
&arena_bin_info[binind];
|
||||
assert(((uintptr_t)ptr - ((uintptr_t)run +
|
||||
(uintptr_t)bin_info->reg0_offset)) %
|
||||
bin_info->reg_size == 0);
|
||||
}
|
||||
#endif
|
||||
malloc_mutex_lock(&bin->lock);
|
||||
arena_dalloc_bin(arena, chunk, ptr, mapelm);
|
||||
malloc_mutex_unlock(&bin->lock);
|
||||
|
||||
113
jemalloc/include/jemalloc/internal/atomic.h
Normal file
113
jemalloc/include/jemalloc/internal/atomic.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/******************************************************************************/
|
||||
#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));
|
||||
}
|
||||
#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));
|
||||
}
|
||||
#else
|
||||
# error "Missing implementation for 32-bit atomic operations"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* JEMALLOC_H_INLINES */
|
||||
/******************************************************************************/
|
||||
184
jemalloc/include/jemalloc/internal/bitmap.h
Normal file
184
jemalloc/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 */
|
||||
/******************************************************************************/
|
||||
@@ -17,6 +17,7 @@
|
||||
extern malloc_mutex_t dss_mtx;
|
||||
|
||||
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_dss_boot(void);
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ extern size_t swap_avail;
|
||||
#endif
|
||||
|
||||
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_swap_enable(const int *fds, unsigned nfds, bool prezeroed);
|
||||
bool chunk_swap_boot(void);
|
||||
|
||||
@@ -31,7 +31,7 @@ struct ckhc_s {
|
||||
|
||||
struct ckh_s {
|
||||
#ifdef JEMALLOC_DEBUG
|
||||
#define CKH_MAGIG 0x3af2489d
|
||||
#define CKH_MAGIC 0x3af2489d
|
||||
uint32_t magic;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ struct ctl_node_s {
|
||||
|
||||
struct ctl_arena_stats_s {
|
||||
bool initialized;
|
||||
unsigned nthreads;
|
||||
size_t pactive;
|
||||
size_t pdirty;
|
||||
#ifdef JEMALLOC_STATS
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
uint64_t hash(const void *key, size_t len, uint64_t seed);
|
||||
#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
|
||||
* public domain by Austin Appleby. See http://murmurhash.googlepages.com/ for
|
||||
@@ -62,7 +62,7 @@ hash(const void *key, size_t len, uint64_t seed)
|
||||
h *= m;
|
||||
h ^= h >> r;
|
||||
|
||||
return h;
|
||||
return (h);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ void *huge_ralloc_no_move(void *ptr, size_t oldsize, size_t size,
|
||||
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);
|
||||
void huge_dalloc(void *ptr, bool unmap);
|
||||
size_t huge_salloc(const void *ptr);
|
||||
#ifdef JEMALLOC_PROF
|
||||
prof_ctx_t *huge_prof_ctx_get(const void *ptr);
|
||||
|
||||
@@ -33,6 +33,10 @@
|
||||
#define JEMALLOC_MANGLE
|
||||
#include "../jemalloc@install_suffix@.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>
|
||||
@@ -55,8 +59,9 @@ extern void (*JEMALLOC_P(malloc_message))(void *wcbopaque, const char *s);
|
||||
* Define a custom assert() in order to reduce the chances of deadlock during
|
||||
* assertion failure.
|
||||
*/
|
||||
#ifdef JEMALLOC_DEBUG
|
||||
# define assert(e) do { \
|
||||
#ifndef assert
|
||||
# ifdef JEMALLOC_DEBUG
|
||||
# define assert(e) do { \
|
||||
if (!(e)) { \
|
||||
char line_buf[UMAX2S_BUFSIZE]; \
|
||||
malloc_write("<jemalloc>: "); \
|
||||
@@ -70,8 +75,15 @@ extern void (*JEMALLOC_P(malloc_message))(void *wcbopaque, const char *s);
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
# else
|
||||
# define assert(e)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef JEMALLOC_DEBUG
|
||||
# define dassert(e) assert(e)
|
||||
#else
|
||||
#define assert(e)
|
||||
# define dassert(e)
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -146,12 +158,19 @@ extern void (*JEMALLOC_P(malloc_message))(void *wcbopaque, const char *s);
|
||||
#define QUANTUM_CEILING(a) \
|
||||
(((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. */
|
||||
#if (!defined(PIC) && !defined(NO_TLS))
|
||||
# define NO_TLS
|
||||
#endif
|
||||
/* Return the smallest long multiple that is >= a. */
|
||||
#define LONG_CEILING(a) \
|
||||
(((a) + LONG_MASK) & ~LONG_MASK)
|
||||
|
||||
#define SIZEOF_PTR (1U << LG_SIZEOF_PTR)
|
||||
#define PTR_MASK (SIZEOF_PTR - 1)
|
||||
|
||||
/* Return the smallest (void *) multiple that is >= a. */
|
||||
#define PTR_CEILING(a) \
|
||||
(((a) + PTR_MASK) & ~PTR_MASK)
|
||||
|
||||
/*
|
||||
* Maximum size of L1 cache line. This is used to avoid cache line aliasing.
|
||||
@@ -198,6 +217,7 @@ extern void (*JEMALLOC_P(malloc_message))(void *wcbopaque, const char *s);
|
||||
#define PAGE_CEILING(s) \
|
||||
(((s) + PAGE_MASK) & ~PAGE_MASK)
|
||||
|
||||
#include "jemalloc/internal/atomic.h"
|
||||
#include "jemalloc/internal/prn.h"
|
||||
#include "jemalloc/internal/ckh.h"
|
||||
#include "jemalloc/internal/stats.h"
|
||||
@@ -206,6 +226,7 @@ extern void (*JEMALLOC_P(malloc_message))(void *wcbopaque, const char *s);
|
||||
#include "jemalloc/internal/mb.h"
|
||||
#include "jemalloc/internal/extent.h"
|
||||
#include "jemalloc/internal/arena.h"
|
||||
#include "jemalloc/internal/bitmap.h"
|
||||
#include "jemalloc/internal/base.h"
|
||||
#include "jemalloc/internal/chunk.h"
|
||||
#include "jemalloc/internal/huge.h"
|
||||
@@ -221,12 +242,14 @@ extern void (*JEMALLOC_P(malloc_message))(void *wcbopaque, const char *s);
|
||||
/******************************************************************************/
|
||||
#define JEMALLOC_H_STRUCTS
|
||||
|
||||
#include "jemalloc/internal/atomic.h"
|
||||
#include "jemalloc/internal/prn.h"
|
||||
#include "jemalloc/internal/ckh.h"
|
||||
#include "jemalloc/internal/stats.h"
|
||||
#include "jemalloc/internal/ctl.h"
|
||||
#include "jemalloc/internal/mutex.h"
|
||||
#include "jemalloc/internal/mb.h"
|
||||
#include "jemalloc/internal/bitmap.h"
|
||||
#include "jemalloc/internal/extent.h"
|
||||
#include "jemalloc/internal/arena.h"
|
||||
#include "jemalloc/internal/base.h"
|
||||
@@ -240,6 +263,13 @@ extern void (*JEMALLOC_P(malloc_message))(void *wcbopaque, const char *s);
|
||||
#endif
|
||||
#include "jemalloc/internal/prof.h"
|
||||
|
||||
#ifdef JEMALLOC_STATS
|
||||
typedef struct {
|
||||
uint64_t allocated;
|
||||
uint64_t deallocated;
|
||||
} thread_allocated_t;
|
||||
#endif
|
||||
|
||||
#undef JEMALLOC_H_STRUCTS
|
||||
/******************************************************************************/
|
||||
#define JEMALLOC_H_EXTERNS
|
||||
@@ -269,6 +299,7 @@ extern size_t lg_pagesize;
|
||||
extern unsigned ncpus;
|
||||
|
||||
extern malloc_mutex_t arenas_lock; /* Protects arenas initialization. */
|
||||
extern pthread_key_t arenas_tsd;
|
||||
#ifndef NO_TLS
|
||||
/*
|
||||
* Map of pthread_self() --> arenas[???], used for selecting an arena to use
|
||||
@@ -278,9 +309,9 @@ 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
|
||||
extern pthread_key_t arenas_tsd;
|
||||
# define ARENA_GET() ((arena_t *)pthread_getspecific(arenas_tsd))
|
||||
# define ARENA_SET(v) do { \
|
||||
pthread_setspecific(arenas_tsd, (void *)(v)); \
|
||||
@@ -295,45 +326,28 @@ extern arena_t **arenas;
|
||||
extern unsigned narenas;
|
||||
|
||||
#ifdef JEMALLOC_STATS
|
||||
typedef struct {
|
||||
uint64_t allocated;
|
||||
uint64_t deallocated;
|
||||
} thread_allocated_t;
|
||||
# ifndef NO_TLS
|
||||
extern __thread thread_allocated_t thread_allocated_tls;
|
||||
# define ALLOCATED_GET() thread_allocated_tls.allocated
|
||||
# define DEALLOCATED_GET() thread_allocated_tls.deallocated
|
||||
# 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;
|
||||
# define ALLOCATED_GET() \
|
||||
(uint64_t)((pthread_getspecific(thread_allocated_tsd) != NULL) \
|
||||
? ((thread_allocated_t *) \
|
||||
pthread_getspecific(thread_allocated_tsd))->allocated : 0)
|
||||
# define DEALLOCATED_GET() \
|
||||
(uint64_t)((pthread_getspecific(thread_allocated_tsd) != NULL) \
|
||||
? ((thread_allocated_t \
|
||||
*)pthread_getspecific(thread_allocated_tsd))->deallocated : \
|
||||
0)
|
||||
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_t *) \
|
||||
pthread_getspecific(thread_allocated_tsd); \
|
||||
if (thread_allocated != NULL) { \
|
||||
thread_allocated->allocated += (a); \
|
||||
thread_allocated->deallocated += (d); \
|
||||
} else { \
|
||||
thread_allocated = (thread_allocated_t *) \
|
||||
imalloc(sizeof(thread_allocated_t)); \
|
||||
if (thread_allocated != NULL) { \
|
||||
pthread_setspecific(thread_allocated_tsd, \
|
||||
thread_allocated); \
|
||||
thread_allocated->allocated = (a); \
|
||||
thread_allocated->deallocated = (d); \
|
||||
} \
|
||||
} \
|
||||
thread_allocated_t *thread_allocated = thread_allocated_get(); \
|
||||
thread_allocated->allocated += (a); \
|
||||
thread_allocated->deallocated += (d); \
|
||||
} while (0)
|
||||
# endif
|
||||
#endif
|
||||
@@ -344,12 +358,14 @@ 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/ckh.h"
|
||||
#include "jemalloc/internal/stats.h"
|
||||
#include "jemalloc/internal/ctl.h"
|
||||
#include "jemalloc/internal/mutex.h"
|
||||
#include "jemalloc/internal/mb.h"
|
||||
#include "jemalloc/internal/bitmap.h"
|
||||
#include "jemalloc/internal/extent.h"
|
||||
#include "jemalloc/internal/arena.h"
|
||||
#include "jemalloc/internal/base.h"
|
||||
@@ -367,6 +383,7 @@ void jemalloc_postfork(void);
|
||||
/******************************************************************************/
|
||||
#define JEMALLOC_H_INLINES
|
||||
|
||||
#include "jemalloc/internal/atomic.h"
|
||||
#include "jemalloc/internal/prn.h"
|
||||
#include "jemalloc/internal/ckh.h"
|
||||
#include "jemalloc/internal/stats.h"
|
||||
@@ -384,6 +401,9 @@ size_t s2u(size_t size);
|
||||
size_t sa2u(size_t size, size_t alignment, size_t *run_size_p);
|
||||
void malloc_write(const char *s);
|
||||
arena_t *choose_arena(void);
|
||||
# if (defined(JEMALLOC_STATS) && defined(NO_TLS))
|
||||
thread_allocated_t *thread_allocated_get(void);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_))
|
||||
@@ -414,10 +434,10 @@ s2u(size_t size)
|
||||
{
|
||||
|
||||
if (size <= small_maxclass)
|
||||
return arenas[0]->bins[small_size2bin[size]].reg_size;
|
||||
return (arena_bin_info[SMALL_SIZE2BIN(size)].reg_size);
|
||||
if (size <= arena_maxclass)
|
||||
return PAGE_CEILING(size);
|
||||
return CHUNK_CEILING(size);
|
||||
return (PAGE_CEILING(size));
|
||||
return (CHUNK_CEILING(size));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -458,10 +478,8 @@ sa2u(size_t size, size_t alignment, size_t *run_size_p)
|
||||
}
|
||||
|
||||
if (usize <= arena_maxclass && alignment <= PAGE_SIZE) {
|
||||
if (usize <= small_maxclass) {
|
||||
return
|
||||
(arenas[0]->bins[small_size2bin[usize]].reg_size);
|
||||
}
|
||||
if (usize <= small_maxclass)
|
||||
return (arena_bin_info[SMALL_SIZE2BIN(usize)].reg_size);
|
||||
return (PAGE_CEILING(usize));
|
||||
} else {
|
||||
size_t run_size;
|
||||
@@ -544,8 +562,22 @@ choose_arena(void)
|
||||
|
||||
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
|
||||
|
||||
#include "jemalloc/internal/bitmap.h"
|
||||
#include "jemalloc/internal/rtree.h"
|
||||
#include "jemalloc/internal/tcache.h"
|
||||
#include "jemalloc/internal/arena.h"
|
||||
@@ -557,7 +589,7 @@ choose_arena(void)
|
||||
#ifndef JEMALLOC_ENABLE_INLINE
|
||||
void *imalloc(size_t size);
|
||||
void *icalloc(size_t size);
|
||||
void *ipalloc(size_t size, size_t alignment, bool zero);
|
||||
void *ipalloc(size_t usize, size_t alignment, bool zero);
|
||||
size_t isalloc(const void *ptr);
|
||||
# ifdef JEMALLOC_IVSALLOC
|
||||
size_t ivsalloc(const void *ptr);
|
||||
@@ -591,28 +623,39 @@ icalloc(size_t size)
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void *
|
||||
ipalloc(size_t size, size_t alignment, bool zero)
|
||||
ipalloc(size_t usize, size_t alignment, bool zero)
|
||||
{
|
||||
void *ret;
|
||||
size_t usize;
|
||||
size_t run_size
|
||||
# ifdef JEMALLOC_CC_SILENCE
|
||||
= 0
|
||||
# endif
|
||||
;
|
||||
|
||||
usize = sa2u(size, alignment, &run_size);
|
||||
if (usize == 0)
|
||||
return (NULL);
|
||||
assert(usize != 0);
|
||||
assert(usize == sa2u(usize, alignment, NULL));
|
||||
|
||||
if (usize <= arena_maxclass && alignment <= PAGE_SIZE)
|
||||
ret = arena_malloc(usize, zero);
|
||||
else if (run_size <= arena_maxclass) {
|
||||
ret = arena_palloc(choose_arena(), usize, run_size, alignment,
|
||||
zero);
|
||||
} else if (alignment <= chunksize)
|
||||
ret = huge_malloc(usize, zero);
|
||||
else
|
||||
ret = huge_palloc(usize, alignment, zero);
|
||||
else {
|
||||
size_t run_size
|
||||
#ifdef JEMALLOC_CC_SILENCE
|
||||
= 0
|
||||
#endif
|
||||
;
|
||||
|
||||
/*
|
||||
* Ideally we would only ever call sa2u() once per aligned
|
||||
* 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.
|
||||
*/
|
||||
sa2u(usize, alignment, &run_size);
|
||||
if (run_size <= arena_maxclass) {
|
||||
ret = arena_palloc(choose_arena(), usize, run_size,
|
||||
alignment, zero);
|
||||
} else if (alignment <= chunksize)
|
||||
ret = huge_malloc(usize, zero);
|
||||
else
|
||||
ret = huge_palloc(usize, alignment, zero);
|
||||
}
|
||||
|
||||
assert(((uintptr_t)ret & (alignment - 1)) == 0);
|
||||
return (ret);
|
||||
@@ -629,7 +672,7 @@ isalloc(const void *ptr)
|
||||
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
||||
if (chunk != ptr) {
|
||||
/* Region. */
|
||||
assert(chunk->arena->magic == ARENA_MAGIC);
|
||||
dassert(chunk->arena->magic == ARENA_MAGIC);
|
||||
|
||||
#ifdef JEMALLOC_PROF
|
||||
ret = arena_salloc_demote(ptr);
|
||||
@@ -666,7 +709,7 @@ idalloc(void *ptr)
|
||||
if (chunk != ptr)
|
||||
arena_dalloc(chunk->arena, chunk, ptr);
|
||||
else
|
||||
huge_dalloc(ptr);
|
||||
huge_dalloc(ptr, true);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void *
|
||||
@@ -683,7 +726,7 @@ iralloc(void *ptr, size_t size, size_t extra, size_t alignment, bool zero,
|
||||
|
||||
if (alignment != 0 && ((uintptr_t)ptr & ((uintptr_t)alignment-1))
|
||||
!= 0) {
|
||||
size_t copysize;
|
||||
size_t usize, copysize;
|
||||
|
||||
/*
|
||||
* Existing object alignment is inadquate; allocate new space
|
||||
@@ -691,12 +734,18 @@ iralloc(void *ptr, size_t size, size_t extra, size_t alignment, bool zero,
|
||||
*/
|
||||
if (no_move)
|
||||
return (NULL);
|
||||
ret = ipalloc(size + extra, alignment, zero);
|
||||
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. */
|
||||
ret = ipalloc(size, alignment, zero);
|
||||
usize = sa2u(size, alignment, NULL);
|
||||
if (usize == 0)
|
||||
return (NULL);
|
||||
ret = ipalloc(usize, alignment, zero);
|
||||
if (ret == NULL)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
void mb_write(void);
|
||||
#endif
|
||||
|
||||
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(MB_C_))
|
||||
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_MB_C_))
|
||||
#ifdef __i386__
|
||||
/*
|
||||
* According to the Intel Architecture Software Developer's Manual, current
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_TYPES
|
||||
|
||||
#ifdef JEMALLOC_OSSPIN
|
||||
typedef OSSpinLock malloc_mutex_t;
|
||||
#else
|
||||
typedef pthread_mutex_t malloc_mutex_t;
|
||||
#endif
|
||||
|
||||
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
|
||||
# define MALLOC_MUTEX_INITIALIZER PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
|
||||
@@ -41,17 +45,26 @@ JEMALLOC_INLINE void
|
||||
malloc_mutex_lock(malloc_mutex_t *mutex)
|
||||
{
|
||||
|
||||
if (isthreaded)
|
||||
if (isthreaded) {
|
||||
#ifdef JEMALLOC_OSSPIN
|
||||
OSSpinLockLock(mutex);
|
||||
#else
|
||||
pthread_mutex_lock(mutex);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE bool
|
||||
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);
|
||||
else
|
||||
#endif
|
||||
} else
|
||||
return (false);
|
||||
}
|
||||
|
||||
@@ -59,8 +72,13 @@ JEMALLOC_INLINE void
|
||||
malloc_mutex_unlock(malloc_mutex_t *mutex)
|
||||
{
|
||||
|
||||
if (isthreaded)
|
||||
if (isthreaded) {
|
||||
#ifdef JEMALLOC_OSSPIN
|
||||
OSSpinLockUnlock(mutex);
|
||||
#else
|
||||
pthread_mutex_unlock(mutex);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -247,8 +247,22 @@ prof_sample_threshold_update(prof_tdata_t *prof_tdata)
|
||||
double u;
|
||||
|
||||
/*
|
||||
* Compute prof_sample_threshold as a geometrically distributed random
|
||||
* 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);
|
||||
@@ -334,7 +348,7 @@ prof_ctx_get(const void *ptr)
|
||||
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
||||
if (chunk != ptr) {
|
||||
/* Region. */
|
||||
assert(chunk->arena->magic == ARENA_MAGIC);
|
||||
dassert(chunk->arena->magic == ARENA_MAGIC);
|
||||
|
||||
ret = arena_prof_ctx_get(ptr);
|
||||
} else
|
||||
@@ -353,7 +367,7 @@ prof_ctx_set(const void *ptr, prof_ctx_t *ctx)
|
||||
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
||||
if (chunk != ptr) {
|
||||
/* Region. */
|
||||
assert(chunk->arena->magic == ARENA_MAGIC);
|
||||
dassert(chunk->arena->magic == ARENA_MAGIC);
|
||||
|
||||
arena_prof_ctx_set(ptr, ctx);
|
||||
} else
|
||||
@@ -374,7 +388,7 @@ prof_sample_accum_update(size_t size)
|
||||
/* Take care to avoid integer overflow. */
|
||||
if (size >= prof_tdata->threshold - prof_tdata->accum) {
|
||||
prof_tdata->accum -= (prof_tdata->threshold - size);
|
||||
/* Compute new prof_sample_threshold. */
|
||||
/* Compute new sample threshold. */
|
||||
prof_sample_threshold_update(prof_tdata);
|
||||
while (prof_tdata->accum >= prof_tdata->threshold) {
|
||||
prof_tdata->accum -= prof_tdata->threshold;
|
||||
|
||||
@@ -49,7 +49,7 @@ 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(RTREE_C_))
|
||||
#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 * \
|
||||
|
||||
@@ -154,6 +154,10 @@ struct chunk_stats_s {
|
||||
|
||||
extern bool opt_stats_print;
|
||||
|
||||
#ifdef JEMALLOC_STATS
|
||||
extern size_t stats_cactive;
|
||||
#endif
|
||||
|
||||
char *u2s(uint64_t x, unsigned base, char *s);
|
||||
#ifdef JEMALLOC_STATS
|
||||
void malloc_cprintf(void (*write)(void *, const char *), void *cbopaque,
|
||||
@@ -166,9 +170,38 @@ void stats_print(void (*write)(void *, const char *), void *cbopaque,
|
||||
|
||||
#endif /* JEMALLOC_H_EXTERNS */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_STATS
|
||||
#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_H_INLINES */
|
||||
/******************************************************************************/
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_TYPES
|
||||
|
||||
typedef struct tcache_bin_info_s tcache_bin_info_t;
|
||||
typedef struct tcache_bin_s tcache_bin_t;
|
||||
typedef struct tcache_s tcache_t;
|
||||
|
||||
@@ -32,15 +33,22 @@ typedef struct tcache_s tcache_t;
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_STRUCTS
|
||||
|
||||
/*
|
||||
* Read-only information associated with each element of tcache_t's tbins array
|
||||
* is stored separately, mainly to reduce memory usage.
|
||||
*/
|
||||
struct tcache_bin_info_s {
|
||||
unsigned ncached_max; /* Upper limit on ncached. */
|
||||
};
|
||||
|
||||
struct tcache_bin_s {
|
||||
# ifdef JEMALLOC_STATS
|
||||
tcache_bin_stats_t tstats;
|
||||
# endif
|
||||
unsigned low_water; /* Min # cached since last GC. */
|
||||
unsigned high_water; /* Max # cached since last GC. */
|
||||
int low_water; /* Min # cached since last GC. */
|
||||
unsigned lg_fill_div; /* Fill (ncached_max >> lg_fill_div). */
|
||||
unsigned ncached; /* # of cached objects. */
|
||||
unsigned ncached_max; /* Upper limit on ncached. */
|
||||
void *avail; /* Chain of available objects. */
|
||||
void **avail; /* Stack of available objects. */
|
||||
};
|
||||
|
||||
struct tcache_s {
|
||||
@@ -54,6 +62,12 @@ struct tcache_s {
|
||||
unsigned ev_cnt; /* Event count since incremental GC. */
|
||||
unsigned next_gc_bin; /* Next bin to GC. */
|
||||
tcache_bin_t tbins[1]; /* Dynamically sized. */
|
||||
/*
|
||||
* The pointer stacks associated with tbins follow as a contiguous
|
||||
* array. During tcache initialization, the avail pointer in each
|
||||
* element of tbins is initialized to point to the proper offset within
|
||||
* this array.
|
||||
*/
|
||||
};
|
||||
|
||||
#endif /* JEMALLOC_H_STRUCTS */
|
||||
@@ -64,6 +78,8 @@ extern bool opt_tcache;
|
||||
extern ssize_t opt_lg_tcache_max;
|
||||
extern ssize_t opt_lg_tcache_gc_sweep;
|
||||
|
||||
extern tcache_bin_info_t *tcache_bin_info;
|
||||
|
||||
/* Map of thread-specific caches. */
|
||||
#ifndef NO_TLS
|
||||
extern __thread tcache_t *tcache_tls
|
||||
@@ -110,7 +126,7 @@ void tcache_destroy(tcache_t *tcache);
|
||||
#ifdef JEMALLOC_STATS
|
||||
void tcache_stats_merge(tcache_t *tcache, arena_t *arena);
|
||||
#endif
|
||||
void tcache_boot(void);
|
||||
bool tcache_boot(void);
|
||||
|
||||
#endif /* JEMALLOC_H_EXTERNS */
|
||||
/******************************************************************************/
|
||||
@@ -169,6 +185,7 @@ tcache_event(tcache_t *tcache)
|
||||
if (tcache->ev_cnt == tcache_gc_incr) {
|
||||
size_t binind = tcache->next_gc_bin;
|
||||
tcache_bin_t *tbin = &tcache->tbins[binind];
|
||||
tcache_bin_info_t *tbin_info = &tcache_bin_info[binind];
|
||||
|
||||
if (tbin->low_water > 0) {
|
||||
/*
|
||||
@@ -192,9 +209,22 @@ tcache_event(tcache_t *tcache)
|
||||
#endif
|
||||
);
|
||||
}
|
||||
/*
|
||||
* Reduce fill count by 2X. Limit lg_fill_div such that
|
||||
* the fill count is always at least 1.
|
||||
*/
|
||||
if ((tbin_info->ncached_max >> (tbin->lg_fill_div+1))
|
||||
>= 1)
|
||||
tbin->lg_fill_div++;
|
||||
} else if (tbin->low_water < 0) {
|
||||
/*
|
||||
* Increase fill count by 2X. Make sure lg_fill_div
|
||||
* stays greater than 0.
|
||||
*/
|
||||
if (tbin->lg_fill_div > 1)
|
||||
tbin->lg_fill_div--;
|
||||
}
|
||||
tbin->low_water = tbin->ncached;
|
||||
tbin->high_water = tbin->ncached;
|
||||
|
||||
tcache->next_gc_bin++;
|
||||
if (tcache->next_gc_bin == nhbins)
|
||||
@@ -208,13 +238,14 @@ tcache_alloc_easy(tcache_bin_t *tbin)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
if (tbin->ncached == 0)
|
||||
if (tbin->ncached == 0) {
|
||||
tbin->low_water = -1;
|
||||
return (NULL);
|
||||
}
|
||||
tbin->ncached--;
|
||||
if (tbin->ncached < tbin->low_water)
|
||||
if ((int)tbin->ncached < tbin->low_water)
|
||||
tbin->low_water = tbin->ncached;
|
||||
ret = tbin->avail;
|
||||
tbin->avail = *(void **)ret;
|
||||
ret = tbin->avail[tbin->ncached];
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@@ -225,7 +256,7 @@ tcache_alloc_small(tcache_t *tcache, size_t size, bool zero)
|
||||
size_t binind;
|
||||
tcache_bin_t *tbin;
|
||||
|
||||
binind = small_size2bin[size];
|
||||
binind = SMALL_SIZE2BIN(size);
|
||||
assert(binind < nbins);
|
||||
tbin = &tcache->tbins[binind];
|
||||
ret = tcache_alloc_easy(tbin);
|
||||
@@ -234,7 +265,7 @@ tcache_alloc_small(tcache_t *tcache, size_t size, bool zero)
|
||||
if (ret == 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) {
|
||||
#ifdef JEMALLOC_FILL
|
||||
@@ -250,7 +281,7 @@ tcache_alloc_small(tcache_t *tcache, size_t size, bool zero)
|
||||
tbin->tstats.nrequests++;
|
||||
#endif
|
||||
#ifdef JEMALLOC_PROF
|
||||
tcache->prof_accumbytes += tcache->arena->bins[binind].reg_size;
|
||||
tcache->prof_accumbytes += arena_bin_info[binind].reg_size;
|
||||
#endif
|
||||
tcache_event(tcache);
|
||||
return (ret);
|
||||
@@ -314,6 +345,7 @@ tcache_dalloc_small(tcache_t *tcache, void *ptr)
|
||||
arena_run_t *run;
|
||||
arena_bin_t *bin;
|
||||
tcache_bin_t *tbin;
|
||||
tcache_bin_info_t *tbin_info;
|
||||
size_t pageind, binind;
|
||||
arena_chunk_map_t *mapelm;
|
||||
|
||||
@@ -325,7 +357,7 @@ tcache_dalloc_small(tcache_t *tcache, void *ptr)
|
||||
mapelm = &chunk->map[pageind-map_bias];
|
||||
run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)((pageind -
|
||||
(mapelm->bits >> PAGE_SHIFT)) << PAGE_SHIFT));
|
||||
assert(run->magic == ARENA_RUN_MAGIC);
|
||||
dassert(run->magic == ARENA_RUN_MAGIC);
|
||||
bin = run->bin;
|
||||
binind = ((uintptr_t)bin - (uintptr_t)&arena->bins) /
|
||||
sizeof(arena_bin_t);
|
||||
@@ -333,23 +365,22 @@ tcache_dalloc_small(tcache_t *tcache, void *ptr)
|
||||
|
||||
#ifdef JEMALLOC_FILL
|
||||
if (opt_junk)
|
||||
memset(ptr, 0x5a, bin->reg_size);
|
||||
memset(ptr, 0x5a, arena_bin_info[binind].reg_size);
|
||||
#endif
|
||||
|
||||
tbin = &tcache->tbins[binind];
|
||||
if (tbin->ncached == tbin->ncached_max) {
|
||||
tcache_bin_flush_small(tbin, binind, (tbin->ncached_max >> 1)
|
||||
tbin_info = &tcache_bin_info[binind];
|
||||
if (tbin->ncached == tbin_info->ncached_max) {
|
||||
tcache_bin_flush_small(tbin, binind, (tbin_info->ncached_max >>
|
||||
1)
|
||||
#if (defined(JEMALLOC_STATS) || defined(JEMALLOC_PROF))
|
||||
, tcache
|
||||
#endif
|
||||
);
|
||||
}
|
||||
assert(tbin->ncached < tbin->ncached_max);
|
||||
*(void **)ptr = tbin->avail;
|
||||
tbin->avail = ptr;
|
||||
assert(tbin->ncached < tbin_info->ncached_max);
|
||||
tbin->avail[tbin->ncached] = ptr;
|
||||
tbin->ncached++;
|
||||
if (tbin->ncached > tbin->high_water)
|
||||
tbin->high_water = tbin->ncached;
|
||||
|
||||
tcache_event(tcache);
|
||||
}
|
||||
@@ -361,6 +392,7 @@ tcache_dalloc_large(tcache_t *tcache, void *ptr, size_t size)
|
||||
arena_chunk_t *chunk;
|
||||
size_t pageind, binind;
|
||||
tcache_bin_t *tbin;
|
||||
tcache_bin_info_t *tbin_info;
|
||||
|
||||
assert((size & PAGE_MASK) == 0);
|
||||
assert(arena_salloc(ptr) > small_maxclass);
|
||||
@@ -377,19 +409,18 @@ tcache_dalloc_large(tcache_t *tcache, void *ptr, size_t size)
|
||||
#endif
|
||||
|
||||
tbin = &tcache->tbins[binind];
|
||||
if (tbin->ncached == tbin->ncached_max) {
|
||||
tcache_bin_flush_large(tbin, binind, (tbin->ncached_max >> 1)
|
||||
tbin_info = &tcache_bin_info[binind];
|
||||
if (tbin->ncached == tbin_info->ncached_max) {
|
||||
tcache_bin_flush_large(tbin, binind, (tbin_info->ncached_max >>
|
||||
1)
|
||||
#if (defined(JEMALLOC_STATS) || defined(JEMALLOC_PROF))
|
||||
, tcache
|
||||
#endif
|
||||
);
|
||||
}
|
||||
assert(tbin->ncached < tbin->ncached_max);
|
||||
*(void **)ptr = tbin->avail;
|
||||
tbin->avail = ptr;
|
||||
assert(tbin->ncached < tbin_info->ncached_max);
|
||||
tbin->avail[tbin->ncached] = ptr;
|
||||
tbin->ncached++;
|
||||
if (tbin->ncached > tbin->high_water)
|
||||
tbin->high_water = tbin->ncached;
|
||||
|
||||
tcache_event(tcache);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ extern "C" {
|
||||
# define JEMALLOC_P(s) s
|
||||
#endif
|
||||
|
||||
#define ALLOCM_LG_ALIGN ((int)0x3f)
|
||||
#define ALLOCM_LG_ALIGN(la) (la)
|
||||
#if LG_SIZEOF_PTR == 2
|
||||
#define ALLOCM_ALIGN(a) (ffs(a)-1)
|
||||
#else
|
||||
|
||||
@@ -24,6 +24,18 @@
|
||||
*/
|
||||
#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. */
|
||||
#undef JEMALLOC_HAVE_ATTR
|
||||
#ifdef JEMALLOC_HAVE_ATTR
|
||||
@@ -53,6 +65,9 @@
|
||||
/* Use libgcc for profile backtracing if defined. */
|
||||
#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
|
||||
* quantum.
|
||||
@@ -115,6 +130,9 @@
|
||||
#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.
|
||||
*
|
||||
@@ -134,4 +152,7 @@
|
||||
/* sizeof(int) == 2^LG_SIZEOF_INT. */
|
||||
#undef LG_SIZEOF_INT
|
||||
|
||||
/* sizeof(long) == 2^LG_SIZEOF_LONG. */
|
||||
#undef LG_SIZEOF_LONG
|
||||
|
||||
#endif /* JEMALLOC_DEFS_H_ */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
2
jemalloc/src/atomic.c
Normal file
2
jemalloc/src/atomic.c
Normal file
@@ -0,0 +1,2 @@
|
||||
#define JEMALLOC_ATOMIC_C_
|
||||
#include "jemalloc/internal/jemalloc_internal.h"
|
||||
90
jemalloc/src/bitmap.c
Normal file
90
jemalloc/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;
|
||||
}
|
||||
}
|
||||
@@ -146,11 +146,6 @@ chunk_boot(void)
|
||||
chunksize_mask = chunksize - 1;
|
||||
chunk_npages = (chunksize >> PAGE_SHIFT);
|
||||
|
||||
#ifdef JEMALLOC_IVSALLOC
|
||||
chunks_rtree = rtree_new((ZU(1) << (LG_SIZEOF_PTR+3)) - opt_lg_chunk);
|
||||
if (chunks_rtree == NULL)
|
||||
return (true);
|
||||
#endif
|
||||
#if (defined(JEMALLOC_STATS) || defined(JEMALLOC_PROF))
|
||||
if (malloc_mutex_init(&chunks_mtx))
|
||||
return (true);
|
||||
@@ -166,6 +161,11 @@ chunk_boot(void)
|
||||
if (chunk_dss_boot())
|
||||
return (true);
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -199,6 +199,22 @@ chunk_dealloc_dss_record(void *chunk, size_t size)
|
||||
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
|
||||
chunk_dealloc_dss(void *chunk, size_t size)
|
||||
{
|
||||
|
||||
@@ -206,13 +206,15 @@ chunk_alloc_mmap_internal(size_t size, bool noreserve)
|
||||
void *
|
||||
chunk_alloc_mmap(size_t size)
|
||||
{
|
||||
return chunk_alloc_mmap_internal(size, false);
|
||||
|
||||
return (chunk_alloc_mmap_internal(size, false));
|
||||
}
|
||||
|
||||
void *
|
||||
chunk_alloc_mmap_noreserve(size_t size)
|
||||
{
|
||||
return chunk_alloc_mmap_internal(size, true);
|
||||
|
||||
return (chunk_alloc_mmap_internal(size, true));
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -184,6 +184,24 @@ chunk_dealloc_swap_record(void *chunk, size_t size)
|
||||
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
|
||||
chunk_dealloc_swap(void *chunk, size_t size)
|
||||
{
|
||||
@@ -219,15 +237,15 @@ chunk_dealloc_swap(void *chunk, size_t size)
|
||||
} else
|
||||
madvise(chunk, size, MADV_DONTNEED);
|
||||
|
||||
#ifdef JEMALLOC_STATS
|
||||
swap_avail += size;
|
||||
#endif
|
||||
ret = false;
|
||||
goto RETURN;
|
||||
}
|
||||
|
||||
ret = true;
|
||||
RETURN:
|
||||
#ifdef JEMALLOC_STATS
|
||||
swap_avail += size;
|
||||
#endif
|
||||
malloc_mutex_unlock(&swap_mtx);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
* respectively.
|
||||
*
|
||||
******************************************************************************/
|
||||
#define CKH_C_
|
||||
#define JEMALLOC_CKH_C_
|
||||
#include "jemalloc/internal/jemalloc_internal.h"
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -73,7 +73,7 @@ ckh_isearch(ckh_t *ckh, const void *key)
|
||||
size_t hash1, hash2, bucket, cell;
|
||||
|
||||
assert(ckh != NULL);
|
||||
assert(ckh->magic = CKH_MAGIG);
|
||||
dassert(ckh->magic == CKH_MAGIC);
|
||||
|
||||
ckh->hash(key, ckh->lg_curbuckets, &hash1, &hash2);
|
||||
|
||||
@@ -262,9 +262,15 @@ ckh_grow(ckh_t *ckh)
|
||||
lg_prevbuckets = ckh->lg_curbuckets;
|
||||
lg_curcells = ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS;
|
||||
while (true) {
|
||||
size_t usize;
|
||||
|
||||
lg_curcells++;
|
||||
tab = (ckhc_t *)ipalloc(sizeof(ckhc_t) << lg_curcells,
|
||||
ZU(1) << LG_CACHELINE, true);
|
||||
usize = sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE, NULL);
|
||||
if (usize == 0) {
|
||||
ret = true;
|
||||
goto RETURN;
|
||||
}
|
||||
tab = (ckhc_t *)ipalloc(usize, CACHELINE, true);
|
||||
if (tab == NULL) {
|
||||
ret = true;
|
||||
goto RETURN;
|
||||
@@ -295,7 +301,7 @@ static void
|
||||
ckh_shrink(ckh_t *ckh)
|
||||
{
|
||||
ckhc_t *tab, *ttab;
|
||||
size_t lg_curcells;
|
||||
size_t lg_curcells, usize;
|
||||
unsigned lg_prevbuckets;
|
||||
|
||||
/*
|
||||
@@ -304,8 +310,10 @@ ckh_shrink(ckh_t *ckh)
|
||||
*/
|
||||
lg_prevbuckets = ckh->lg_curbuckets;
|
||||
lg_curcells = ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS - 1;
|
||||
tab = (ckhc_t *)ipalloc(sizeof(ckhc_t) << lg_curcells,
|
||||
ZU(1) << LG_CACHELINE, true);
|
||||
usize = sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE, NULL);
|
||||
if (usize == 0)
|
||||
return;
|
||||
tab = (ckhc_t *)ipalloc(usize, CACHELINE, true);
|
||||
if (tab == NULL) {
|
||||
/*
|
||||
* An OOM error isn't worth propagating, since it doesn't
|
||||
@@ -340,7 +348,7 @@ bool
|
||||
ckh_new(ckh_t *ckh, size_t minitems, ckh_hash_t *hash, ckh_keycomp_t *keycomp)
|
||||
{
|
||||
bool ret;
|
||||
size_t mincells;
|
||||
size_t mincells, usize;
|
||||
unsigned lg_mincells;
|
||||
|
||||
assert(minitems > 0);
|
||||
@@ -375,15 +383,19 @@ ckh_new(ckh_t *ckh, size_t minitems, ckh_hash_t *hash, ckh_keycomp_t *keycomp)
|
||||
ckh->hash = hash;
|
||||
ckh->keycomp = keycomp;
|
||||
|
||||
ckh->tab = (ckhc_t *)ipalloc(sizeof(ckhc_t) << lg_mincells,
|
||||
(ZU(1) << LG_CACHELINE), true);
|
||||
usize = sa2u(sizeof(ckhc_t) << lg_mincells, CACHELINE, NULL);
|
||||
if (usize == 0) {
|
||||
ret = true;
|
||||
goto RETURN;
|
||||
}
|
||||
ckh->tab = (ckhc_t *)ipalloc(usize, CACHELINE, true);
|
||||
if (ckh->tab == NULL) {
|
||||
ret = true;
|
||||
goto RETURN;
|
||||
}
|
||||
|
||||
#ifdef JEMALLOC_DEBUG
|
||||
ckh->magic = CKH_MAGIG;
|
||||
ckh->magic = CKH_MAGIC;
|
||||
#endif
|
||||
|
||||
ret = false;
|
||||
@@ -396,7 +408,7 @@ ckh_delete(ckh_t *ckh)
|
||||
{
|
||||
|
||||
assert(ckh != NULL);
|
||||
assert(ckh->magic = CKH_MAGIG);
|
||||
dassert(ckh->magic == CKH_MAGIC);
|
||||
|
||||
#ifdef CKH_VERBOSE
|
||||
malloc_printf(
|
||||
@@ -421,7 +433,7 @@ ckh_count(ckh_t *ckh)
|
||||
{
|
||||
|
||||
assert(ckh != NULL);
|
||||
assert(ckh->magic = CKH_MAGIG);
|
||||
dassert(ckh->magic == CKH_MAGIC);
|
||||
|
||||
return (ckh->count);
|
||||
}
|
||||
@@ -452,7 +464,7 @@ ckh_insert(ckh_t *ckh, const void *key, const void *data)
|
||||
bool ret;
|
||||
|
||||
assert(ckh != NULL);
|
||||
assert(ckh->magic = CKH_MAGIG);
|
||||
dassert(ckh->magic == CKH_MAGIC);
|
||||
assert(ckh_search(ckh, key, NULL, NULL));
|
||||
|
||||
#ifdef CKH_COUNT
|
||||
@@ -477,7 +489,7 @@ ckh_remove(ckh_t *ckh, const void *searchkey, void **key, void **data)
|
||||
size_t cell;
|
||||
|
||||
assert(ckh != NULL);
|
||||
assert(ckh->magic = CKH_MAGIG);
|
||||
dassert(ckh->magic == CKH_MAGIC);
|
||||
|
||||
cell = ckh_isearch(ckh, searchkey);
|
||||
if (cell != SIZE_T_MAX) {
|
||||
@@ -509,7 +521,7 @@ ckh_search(ckh_t *ckh, const void *searchkey, void **key, void **data)
|
||||
size_t cell;
|
||||
|
||||
assert(ckh != NULL);
|
||||
assert(ckh->magic = CKH_MAGIG);
|
||||
dassert(ckh->magic == CKH_MAGIC);
|
||||
|
||||
cell = ckh_isearch(ckh, searchkey);
|
||||
if (cell != SIZE_T_MAX) {
|
||||
|
||||
@@ -4,6 +4,13 @@
|
||||
/******************************************************************************/
|
||||
/* Data. */
|
||||
|
||||
/*
|
||||
* ctl_mtx protects the following:
|
||||
* - ctl_stats.*
|
||||
* - opt_prof_active
|
||||
* - swap_enabled
|
||||
* - swap_prezeroed
|
||||
*/
|
||||
static malloc_mutex_t ctl_mtx;
|
||||
static bool ctl_initialized;
|
||||
static uint64_t ctl_epoch;
|
||||
@@ -44,7 +51,9 @@ CTL_PROTO(tcache_flush)
|
||||
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_dss)
|
||||
@@ -173,6 +182,7 @@ CTL_PROTO(stats_arenas_i_lruns_j_highruns)
|
||||
CTL_PROTO(stats_arenas_i_lruns_j_curruns)
|
||||
INDEX_PROTO(stats_arenas_i_lruns_j)
|
||||
#endif
|
||||
CTL_PROTO(stats_arenas_i_nthreads)
|
||||
CTL_PROTO(stats_arenas_i_pactive)
|
||||
CTL_PROTO(stats_arenas_i_pdirty)
|
||||
#ifdef JEMALLOC_STATS
|
||||
@@ -183,6 +193,7 @@ CTL_PROTO(stats_arenas_i_purged)
|
||||
#endif
|
||||
INDEX_PROTO(stats_arenas_i)
|
||||
#ifdef JEMALLOC_STATS
|
||||
CTL_PROTO(stats_cactive)
|
||||
CTL_PROTO(stats_allocated)
|
||||
CTL_PROTO(stats_active)
|
||||
CTL_PROTO(stats_mapped)
|
||||
@@ -223,7 +234,9 @@ static const ctl_node_t thread_node[] = {
|
||||
#ifdef JEMALLOC_STATS
|
||||
,
|
||||
{NAME("allocated"), CTL(thread_allocated)},
|
||||
{NAME("deallocated"), CTL(thread_deallocated)}
|
||||
{NAME("allocatedp"), CTL(thread_allocatedp)},
|
||||
{NAME("deallocated"), CTL(thread_deallocated)},
|
||||
{NAME("deallocatedp"), CTL(thread_deallocatedp)}
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -423,6 +436,7 @@ static const ctl_node_t stats_arenas_i_lruns_node[] = {
|
||||
#endif
|
||||
|
||||
static const ctl_node_t stats_arenas_i_node[] = {
|
||||
{NAME("nthreads"), CTL(stats_arenas_i_nthreads)},
|
||||
{NAME("pactive"), CTL(stats_arenas_i_pactive)},
|
||||
{NAME("pdirty"), CTL(stats_arenas_i_pdirty)}
|
||||
#ifdef JEMALLOC_STATS
|
||||
@@ -447,6 +461,7 @@ static const ctl_node_t stats_arenas_node[] = {
|
||||
|
||||
static const ctl_node_t stats_node[] = {
|
||||
#ifdef JEMALLOC_STATS
|
||||
{NAME("cactive"), CTL(stats_cactive)},
|
||||
{NAME("allocated"), CTL(stats_allocated)},
|
||||
{NAME("active"), CTL(stats_active)},
|
||||
{NAME("mapped"), CTL(stats_mapped)},
|
||||
@@ -609,6 +624,7 @@ ctl_arena_refresh(arena_t *arena, unsigned i)
|
||||
|
||||
ctl_arena_clear(astats);
|
||||
|
||||
sstats->nthreads += astats->nthreads;
|
||||
#ifdef JEMALLOC_STATS
|
||||
ctl_arena_stats_amerge(astats, arena);
|
||||
/* Merge into sum stats as well. */
|
||||
@@ -646,10 +662,17 @@ ctl_refresh(void)
|
||||
* Clear sum stats, since they will be merged into by
|
||||
* ctl_arena_refresh().
|
||||
*/
|
||||
ctl_stats.arenas[narenas].nthreads = 0;
|
||||
ctl_arena_clear(&ctl_stats.arenas[narenas]);
|
||||
|
||||
malloc_mutex_lock(&arenas_lock);
|
||||
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);
|
||||
for (i = 0; i < narenas; i++) {
|
||||
bool initialized = (tarenas[i] != NULL);
|
||||
@@ -680,7 +703,9 @@ ctl_refresh(void)
|
||||
static bool
|
||||
ctl_init(void)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
malloc_mutex_lock(&ctl_mtx);
|
||||
if (ctl_initialized == false) {
|
||||
#ifdef JEMALLOC_STATS
|
||||
unsigned i;
|
||||
@@ -692,8 +717,10 @@ ctl_init(void)
|
||||
*/
|
||||
ctl_stats.arenas = (ctl_arena_stats_t *)base_alloc(
|
||||
(narenas + 1) * sizeof(ctl_arena_stats_t));
|
||||
if (ctl_stats.arenas == NULL)
|
||||
return (true);
|
||||
if (ctl_stats.arenas == NULL) {
|
||||
ret = true;
|
||||
goto RETURN;
|
||||
}
|
||||
memset(ctl_stats.arenas, 0, (narenas + 1) *
|
||||
sizeof(ctl_arena_stats_t));
|
||||
|
||||
@@ -704,8 +731,10 @@ ctl_init(void)
|
||||
*/
|
||||
#ifdef JEMALLOC_STATS
|
||||
for (i = 0; i <= narenas; i++) {
|
||||
if (ctl_arena_init(&ctl_stats.arenas[i]))
|
||||
return (true);
|
||||
if (ctl_arena_init(&ctl_stats.arenas[i])) {
|
||||
ret = true;
|
||||
goto RETURN;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
ctl_stats.arenas[narenas].initialized = true;
|
||||
@@ -715,7 +744,10 @@ ctl_init(void)
|
||||
ctl_initialized = true;
|
||||
}
|
||||
|
||||
return (false);
|
||||
ret = false;
|
||||
RETURN:
|
||||
malloc_mutex_unlock(&ctl_mtx);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -825,8 +857,7 @@ ctl_byname(const char *name, void *oldp, size_t *oldlenp, void *newp,
|
||||
ctl_node_t const *nodes[CTL_MAX_DEPTH];
|
||||
size_t mib[CTL_MAX_DEPTH];
|
||||
|
||||
malloc_mutex_lock(&ctl_mtx);
|
||||
if (ctl_init()) {
|
||||
if (ctl_initialized == false && ctl_init()) {
|
||||
ret = EAGAIN;
|
||||
goto RETURN;
|
||||
}
|
||||
@@ -841,10 +872,9 @@ ctl_byname(const char *name, void *oldp, size_t *oldlenp, void *newp,
|
||||
ret = ENOENT;
|
||||
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:
|
||||
malloc_mutex_unlock(&ctl_mtx);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
@@ -853,16 +883,13 @@ ctl_nametomib(const char *name, size_t *mibp, size_t *miblenp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
malloc_mutex_lock(&ctl_mtx);
|
||||
if (ctl_init()) {
|
||||
if (ctl_initialized == false && ctl_init()) {
|
||||
ret = EAGAIN;
|
||||
goto RETURN;
|
||||
}
|
||||
|
||||
ret = ctl_lookup(name, NULL, mibp, miblenp);
|
||||
|
||||
RETURN:
|
||||
malloc_mutex_unlock(&ctl_mtx);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
@@ -874,8 +901,7 @@ ctl_bymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
||||
const ctl_node_t *node;
|
||||
size_t i;
|
||||
|
||||
malloc_mutex_lock(&ctl_mtx);
|
||||
if (ctl_init()) {
|
||||
if (ctl_initialized == false && ctl_init()) {
|
||||
ret = EAGAIN;
|
||||
goto RETURN;
|
||||
}
|
||||
@@ -912,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);
|
||||
|
||||
RETURN:
|
||||
malloc_mutex_unlock(&ctl_mtx);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
@@ -975,6 +1000,29 @@ ctl_boot(void)
|
||||
|
||||
#define CTL_RO_GEN(n, v, t) \
|
||||
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, \
|
||||
void *newp, size_t newlen) \
|
||||
{ \
|
||||
@@ -1024,7 +1072,7 @@ RETURN: \
|
||||
return (ret); \
|
||||
}
|
||||
|
||||
CTL_RO_GEN(version, JEMALLOC_VERSION, const char *)
|
||||
CTL_RO_NL_GEN(version, JEMALLOC_VERSION, const char *)
|
||||
|
||||
static int
|
||||
epoch_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
||||
@@ -1033,6 +1081,7 @@ epoch_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
||||
int ret;
|
||||
uint64_t newval;
|
||||
|
||||
malloc_mutex_lock(&ctl_mtx);
|
||||
newval = 0;
|
||||
WRITE(newval, uint64_t);
|
||||
if (newval != 0)
|
||||
@@ -1041,6 +1090,7 @@ epoch_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
||||
|
||||
ret = 0;
|
||||
RETURN:
|
||||
malloc_mutex_unlock(&ctl_mtx);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@@ -1076,8 +1126,8 @@ thread_arena_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
||||
unsigned newind, oldind;
|
||||
|
||||
newind = oldind = choose_arena()->ind;
|
||||
WRITE(oldind, unsigned);
|
||||
READ(newind, unsigned);
|
||||
WRITE(newind, unsigned);
|
||||
READ(oldind, unsigned);
|
||||
if (newind != oldind) {
|
||||
arena_t *arena;
|
||||
|
||||
@@ -1091,6 +1141,8 @@ thread_arena_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
||||
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;
|
||||
@@ -1099,6 +1151,11 @@ thread_arena_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
||||
|
||||
/* Set new arena association. */
|
||||
ARENA_SET(arena);
|
||||
{
|
||||
tcache_t *tcache = TCACHE_GET();
|
||||
if (tcache != NULL)
|
||||
tcache->arena = arena;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
@@ -1107,8 +1164,10 @@ RETURN:
|
||||
}
|
||||
|
||||
#ifdef JEMALLOC_STATS
|
||||
CTL_RO_GEN(thread_allocated, ALLOCATED_GET(), uint64_t);
|
||||
CTL_RO_GEN(thread_deallocated, DEALLOCATED_GET(), uint64_t);
|
||||
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
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -1205,48 +1264,48 @@ CTL_RO_FALSE_GEN(config_xmalloc)
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
CTL_RO_GEN(opt_abort, opt_abort, 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_chunk, opt_lg_chunk, size_t)
|
||||
CTL_RO_GEN(opt_narenas, opt_narenas, size_t)
|
||||
CTL_RO_GEN(opt_lg_dirty_mult, opt_lg_dirty_mult, ssize_t)
|
||||
CTL_RO_GEN(opt_stats_print, opt_stats_print, 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
|
||||
CTL_RO_GEN(opt_junk, opt_junk, bool)
|
||||
CTL_RO_GEN(opt_zero, opt_zero, bool)
|
||||
CTL_RO_NL_GEN(opt_junk, opt_junk, bool)
|
||||
CTL_RO_NL_GEN(opt_zero, opt_zero, bool)
|
||||
#endif
|
||||
#ifdef JEMALLOC_SYSV
|
||||
CTL_RO_GEN(opt_sysv, opt_sysv, bool)
|
||||
CTL_RO_NL_GEN(opt_sysv, opt_sysv, bool)
|
||||
#endif
|
||||
#ifdef JEMALLOC_XMALLOC
|
||||
CTL_RO_GEN(opt_xmalloc, opt_xmalloc, bool)
|
||||
CTL_RO_NL_GEN(opt_xmalloc, opt_xmalloc, bool)
|
||||
#endif
|
||||
#ifdef JEMALLOC_TCACHE
|
||||
CTL_RO_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_tcache, opt_tcache, bool)
|
||||
CTL_RO_NL_GEN(opt_lg_tcache_gc_sweep, opt_lg_tcache_gc_sweep, ssize_t)
|
||||
#endif
|
||||
#ifdef JEMALLOC_PROF
|
||||
CTL_RO_GEN(opt_prof, opt_prof, bool)
|
||||
CTL_RO_GEN(opt_prof_prefix, opt_prof_prefix, const char *)
|
||||
CTL_RO_GEN(opt_prof_active, opt_prof_active, bool)
|
||||
CTL_RO_GEN(opt_lg_prof_bt_max, opt_lg_prof_bt_max, size_t)
|
||||
CTL_RO_GEN(opt_lg_prof_sample, opt_lg_prof_sample, size_t)
|
||||
CTL_RO_GEN(opt_lg_prof_interval, opt_lg_prof_interval, ssize_t)
|
||||
CTL_RO_GEN(opt_prof_gdump, opt_prof_gdump, bool)
|
||||
CTL_RO_GEN(opt_prof_leak, opt_prof_leak, bool)
|
||||
CTL_RO_GEN(opt_prof_accum, opt_prof_accum, bool)
|
||||
CTL_RO_GEN(opt_lg_prof_tcmax, opt_lg_prof_tcmax, ssize_t)
|
||||
CTL_RO_NL_GEN(opt_prof, opt_prof, bool)
|
||||
CTL_RO_NL_GEN(opt_prof_prefix, opt_prof_prefix, const char *)
|
||||
CTL_RO_GEN(opt_prof_active, opt_prof_active, bool) /* Mutable. */
|
||||
CTL_RO_NL_GEN(opt_lg_prof_bt_max, opt_lg_prof_bt_max, size_t)
|
||||
CTL_RO_NL_GEN(opt_lg_prof_sample, opt_lg_prof_sample, size_t)
|
||||
CTL_RO_NL_GEN(opt_lg_prof_interval, opt_lg_prof_interval, ssize_t)
|
||||
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
|
||||
#ifdef JEMALLOC_SWAP
|
||||
CTL_RO_GEN(opt_overcommit, opt_overcommit, bool)
|
||||
CTL_RO_NL_GEN(opt_overcommit, opt_overcommit, bool)
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
CTL_RO_GEN(arenas_bin_i_size, arenas[0]->bins[mib[2]].reg_size, size_t)
|
||||
CTL_RO_GEN(arenas_bin_i_nregs, arenas[0]->bins[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_size, arena_bin_info[mib[2]].reg_size, size_t)
|
||||
CTL_RO_NL_GEN(arenas_bin_i_nregs, arena_bin_info[mib[2]].nregs, uint32_t)
|
||||
CTL_RO_NL_GEN(arenas_bin_i_run_size, arena_bin_info[mib[2]].run_size, size_t)
|
||||
const ctl_node_t *
|
||||
arenas_bin_i_index(const size_t *mib, size_t miblen, size_t i)
|
||||
{
|
||||
@@ -1256,7 +1315,7 @@ arenas_bin_i_index(const size_t *mib, size_t miblen, size_t i)
|
||||
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 *
|
||||
arenas_lrun_i_index(const size_t *mib, size_t miblen, size_t i)
|
||||
{
|
||||
@@ -1266,7 +1325,7 @@ arenas_lrun_i_index(const size_t *mib, size_t miblen, size_t i)
|
||||
return (super_arenas_lrun_i_node);
|
||||
}
|
||||
|
||||
CTL_RO_GEN(arenas_narenas, narenas, unsigned)
|
||||
CTL_RO_NL_GEN(arenas_narenas, narenas, unsigned)
|
||||
|
||||
static int
|
||||
arenas_initialized_ctl(const size_t *mib, size_t miblen, void *oldp,
|
||||
@@ -1275,6 +1334,7 @@ arenas_initialized_ctl(const size_t *mib, size_t miblen, void *oldp,
|
||||
int ret;
|
||||
unsigned nread, i;
|
||||
|
||||
malloc_mutex_lock(&ctl_mtx);
|
||||
READONLY();
|
||||
if (*oldlenp != narenas * sizeof(bool)) {
|
||||
ret = EINVAL;
|
||||
@@ -1289,36 +1349,37 @@ arenas_initialized_ctl(const size_t *mib, size_t miblen, void *oldp,
|
||||
((bool *)oldp)[i] = ctl_stats.arenas[i].initialized;
|
||||
|
||||
RETURN:
|
||||
malloc_mutex_unlock(&ctl_mtx);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
CTL_RO_GEN(arenas_quantum, QUANTUM, size_t)
|
||||
CTL_RO_GEN(arenas_cacheline, CACHELINE, size_t)
|
||||
CTL_RO_GEN(arenas_subpage, SUBPAGE, size_t)
|
||||
CTL_RO_GEN(arenas_pagesize, PAGE_SIZE, size_t)
|
||||
CTL_RO_GEN(arenas_chunksize, chunksize, size_t)
|
||||
CTL_RO_NL_GEN(arenas_quantum, QUANTUM, size_t)
|
||||
CTL_RO_NL_GEN(arenas_cacheline, CACHELINE, size_t)
|
||||
CTL_RO_NL_GEN(arenas_subpage, SUBPAGE, size_t)
|
||||
CTL_RO_NL_GEN(arenas_pagesize, PAGE_SIZE, size_t)
|
||||
CTL_RO_NL_GEN(arenas_chunksize, chunksize, size_t)
|
||||
#ifdef JEMALLOC_TINY
|
||||
CTL_RO_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_min, (1U << LG_TINY_MIN), size_t)
|
||||
CTL_RO_NL_GEN(arenas_tspace_max, (qspace_min >> 1), size_t)
|
||||
#endif
|
||||
CTL_RO_GEN(arenas_qspace_min, qspace_min, size_t)
|
||||
CTL_RO_GEN(arenas_qspace_max, qspace_max, size_t)
|
||||
CTL_RO_GEN(arenas_cspace_min, cspace_min, size_t)
|
||||
CTL_RO_GEN(arenas_cspace_max, cspace_max, size_t)
|
||||
CTL_RO_GEN(arenas_sspace_min, sspace_min, size_t)
|
||||
CTL_RO_GEN(arenas_sspace_max, sspace_max, size_t)
|
||||
CTL_RO_NL_GEN(arenas_qspace_min, qspace_min, size_t)
|
||||
CTL_RO_NL_GEN(arenas_qspace_max, qspace_max, size_t)
|
||||
CTL_RO_NL_GEN(arenas_cspace_min, cspace_min, size_t)
|
||||
CTL_RO_NL_GEN(arenas_cspace_max, cspace_max, size_t)
|
||||
CTL_RO_NL_GEN(arenas_sspace_min, sspace_min, size_t)
|
||||
CTL_RO_NL_GEN(arenas_sspace_max, sspace_max, size_t)
|
||||
#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
|
||||
CTL_RO_GEN(arenas_ntbins, ntbins, unsigned)
|
||||
CTL_RO_GEN(arenas_nqbins, nqbins, unsigned)
|
||||
CTL_RO_GEN(arenas_ncbins, ncbins, unsigned)
|
||||
CTL_RO_GEN(arenas_nsbins, nsbins, unsigned)
|
||||
CTL_RO_GEN(arenas_nbins, nbins, unsigned)
|
||||
CTL_RO_NL_GEN(arenas_ntbins, ntbins, unsigned)
|
||||
CTL_RO_NL_GEN(arenas_nqbins, nqbins, unsigned)
|
||||
CTL_RO_NL_GEN(arenas_ncbins, ncbins, unsigned)
|
||||
CTL_RO_NL_GEN(arenas_nsbins, nsbins, unsigned)
|
||||
CTL_RO_NL_GEN(arenas_nbins, nbins, unsigned)
|
||||
#ifdef JEMALLOC_TCACHE
|
||||
CTL_RO_GEN(arenas_nhbins, nhbins, unsigned)
|
||||
CTL_RO_NL_GEN(arenas_nhbins, nhbins, unsigned)
|
||||
#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,
|
||||
@@ -1368,6 +1429,7 @@ prof_active_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
||||
int ret;
|
||||
bool oldval;
|
||||
|
||||
malloc_mutex_lock(&ctl_mtx); /* Protect opt_prof_active. */
|
||||
oldval = opt_prof_active;
|
||||
if (newp != NULL) {
|
||||
/*
|
||||
@@ -1382,6 +1444,7 @@ prof_active_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
||||
|
||||
ret = 0;
|
||||
RETURN:
|
||||
malloc_mutex_unlock(&ctl_mtx);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@@ -1405,7 +1468,7 @@ RETURN:
|
||||
return (ret);
|
||||
}
|
||||
|
||||
CTL_RO_GEN(prof_interval, prof_interval, uint64_t)
|
||||
CTL_RO_NL_GEN(prof_interval, prof_interval, uint64_t)
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -1487,6 +1550,7 @@ stats_arenas_i_lruns_j_index(const size_t *mib, size_t miblen, size_t j)
|
||||
}
|
||||
|
||||
#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_pdirty, ctl_stats.arenas[mib[2]].pdirty, size_t)
|
||||
#ifdef JEMALLOC_STATS
|
||||
@@ -1503,13 +1567,22 @@ CTL_RO_GEN(stats_arenas_i_purged, ctl_stats.arenas[mib[2]].astats.purged,
|
||||
const ctl_node_t *
|
||||
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)
|
||||
return (NULL);
|
||||
return (super_stats_arenas_i_node);
|
||||
malloc_mutex_lock(&ctl_mtx);
|
||||
if (ctl_stats.arenas[i].initialized == false) {
|
||||
ret = NULL;
|
||||
goto RETURN;
|
||||
}
|
||||
|
||||
ret = super_stats_arenas_i_node;
|
||||
RETURN:
|
||||
malloc_mutex_unlock(&ctl_mtx);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#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_active, ctl_stats.active, size_t)
|
||||
CTL_RO_GEN(stats_mapped, ctl_stats.mapped, size_t)
|
||||
@@ -1528,6 +1601,7 @@ swap_prezeroed_ctl(const size_t *mib, size_t miblen, void *oldp,
|
||||
{
|
||||
int ret;
|
||||
|
||||
malloc_mutex_lock(&ctl_mtx);
|
||||
if (swap_enabled) {
|
||||
READONLY();
|
||||
} else {
|
||||
@@ -1545,6 +1619,7 @@ swap_prezeroed_ctl(const size_t *mib, size_t miblen, void *oldp,
|
||||
|
||||
ret = 0;
|
||||
RETURN:
|
||||
malloc_mutex_unlock(&ctl_mtx);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@@ -1556,6 +1631,7 @@ swap_fds_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
||||
{
|
||||
int ret;
|
||||
|
||||
malloc_mutex_lock(&ctl_mtx);
|
||||
if (swap_enabled) {
|
||||
READONLY();
|
||||
} else if (newp != NULL) {
|
||||
@@ -1586,6 +1662,7 @@ swap_fds_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
||||
|
||||
ret = 0;
|
||||
RETURN:
|
||||
malloc_mutex_unlock(&ctl_mtx);
|
||||
return (ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#define HASH_C_
|
||||
#define JEMALLOC_HASH_C_
|
||||
#include "jemalloc/internal/jemalloc_internal.h"
|
||||
|
||||
@@ -50,6 +50,7 @@ huge_malloc(size_t size, bool zero)
|
||||
malloc_mutex_lock(&huge_mtx);
|
||||
extent_tree_ad_insert(&huge, node);
|
||||
#ifdef JEMALLOC_STATS
|
||||
stats_cactive_add(csize);
|
||||
huge_nmalloc++;
|
||||
huge_allocated += csize;
|
||||
#endif
|
||||
@@ -83,7 +84,7 @@ huge_palloc(size_t size, size_t alignment, bool zero)
|
||||
* alignment, in order to assure the alignment can be achieved, then
|
||||
* unmap leading and trailing chunks.
|
||||
*/
|
||||
assert(alignment >= chunksize);
|
||||
assert(alignment > chunksize);
|
||||
|
||||
chunk_size = CHUNK_CEILING(size);
|
||||
|
||||
@@ -134,6 +135,7 @@ huge_palloc(size_t size, size_t alignment, bool zero)
|
||||
malloc_mutex_lock(&huge_mtx);
|
||||
extent_tree_ad_insert(&huge, node);
|
||||
#ifdef JEMALLOC_STATS
|
||||
stats_cactive_add(chunk_size);
|
||||
huge_nmalloc++;
|
||||
huge_allocated += chunk_size;
|
||||
#endif
|
||||
@@ -192,7 +194,7 @@ huge_ralloc(void *ptr, size_t oldsize, size_t size, size_t extra,
|
||||
* different size class. In that case, fall back to allocating new
|
||||
* space and copying.
|
||||
*/
|
||||
if (alignment != 0)
|
||||
if (alignment > chunksize)
|
||||
ret = huge_palloc(size + extra, alignment, zero);
|
||||
else
|
||||
ret = huge_malloc(size + extra, zero);
|
||||
@@ -201,7 +203,7 @@ huge_ralloc(void *ptr, size_t oldsize, size_t size, size_t extra,
|
||||
if (extra == 0)
|
||||
return (NULL);
|
||||
/* Try again, this time without extra. */
|
||||
if (alignment != 0)
|
||||
if (alignment > chunksize)
|
||||
ret = huge_palloc(size, alignment, zero);
|
||||
else
|
||||
ret = huge_malloc(size, zero);
|
||||
@@ -215,13 +217,56 @@ huge_ralloc(void *ptr, size_t oldsize, size_t size, size_t extra,
|
||||
* expectation that the extra bytes will be reliably preserved.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
huge_dalloc(void *ptr)
|
||||
huge_dalloc(void *ptr, bool unmap)
|
||||
{
|
||||
extent_node_t *node, key;
|
||||
|
||||
@@ -235,20 +280,23 @@ huge_dalloc(void *ptr)
|
||||
extent_tree_ad_remove(&huge, node);
|
||||
|
||||
#ifdef JEMALLOC_STATS
|
||||
stats_cactive_sub(node->size);
|
||||
huge_ndalloc++;
|
||||
huge_allocated -= node->size;
|
||||
#endif
|
||||
|
||||
malloc_mutex_unlock(&huge_mtx);
|
||||
|
||||
if (unmap) {
|
||||
/* Unmap chunk. */
|
||||
#ifdef JEMALLOC_FILL
|
||||
#if (defined(JEMALLOC_SWAP) || defined(JEMALLOC_DSS))
|
||||
if (opt_junk)
|
||||
memset(node->addr, 0x5a, node->size);
|
||||
if (opt_junk)
|
||||
memset(node->addr, 0x5a, node->size);
|
||||
#endif
|
||||
#endif
|
||||
chunk_dealloc(node->addr, node->size);
|
||||
chunk_dealloc(node->addr, node->size);
|
||||
}
|
||||
|
||||
base_node_dealloc(node);
|
||||
}
|
||||
|
||||
@@ -7,12 +7,10 @@
|
||||
malloc_mutex_t arenas_lock;
|
||||
arena_t **arenas;
|
||||
unsigned narenas;
|
||||
static unsigned next_arena;
|
||||
|
||||
pthread_key_t arenas_tsd;
|
||||
#ifndef NO_TLS
|
||||
__thread arena_t *arenas_tls JEMALLOC_ATTR(tls_model("initial-exec"));
|
||||
#else
|
||||
pthread_key_t arenas_tsd;
|
||||
#endif
|
||||
|
||||
#ifdef JEMALLOC_STATS
|
||||
@@ -30,7 +28,13 @@ static bool malloc_initialized = false;
|
||||
static pthread_t malloc_initializer = (unsigned long)0;
|
||||
|
||||
/* Used to avoid initialization races. */
|
||||
static malloc_mutex_t init_lock = MALLOC_MUTEX_INITIALIZER;
|
||||
static malloc_mutex_t init_lock =
|
||||
#ifdef JEMALLOC_OSSPIN
|
||||
0
|
||||
#else
|
||||
MALLOC_MUTEX_INITIALIZER
|
||||
#endif
|
||||
;
|
||||
|
||||
#ifdef DYNAMIC_PAGE_SHIFT
|
||||
size_t pagesize;
|
||||
@@ -70,6 +74,7 @@ size_t opt_narenas = 0;
|
||||
static void wrtmessage(void *cbopaque, const char *s);
|
||||
static void stats_print_atexit(void);
|
||||
static unsigned malloc_ncpus(void);
|
||||
static void arenas_cleanup(void *arg);
|
||||
#if (defined(JEMALLOC_STATS) && defined(NO_TLS))
|
||||
static void thread_allocated_cleanup(void *arg);
|
||||
#endif
|
||||
@@ -147,13 +152,53 @@ choose_arena_hard(void)
|
||||
arena_t *ret;
|
||||
|
||||
if (narenas > 1) {
|
||||
unsigned i, choose, first_null;
|
||||
|
||||
choose = 0;
|
||||
first_null = narenas;
|
||||
malloc_mutex_lock(&arenas_lock);
|
||||
if ((ret = arenas[next_arena]) == NULL)
|
||||
ret = arenas_extend(next_arena);
|
||||
next_arena = (next_arena + 1) % narenas;
|
||||
assert(arenas[0] != NULL);
|
||||
for (i = 1; i < narenas; i++) {
|
||||
if (arenas[i] != NULL) {
|
||||
/*
|
||||
* Choose the first arena that has the lowest
|
||||
* number of threads assigned to it.
|
||||
*/
|
||||
if (arenas[i]->nthreads <
|
||||
arenas[choose]->nthreads)
|
||||
choose = i;
|
||||
} else if (first_null == narenas) {
|
||||
/*
|
||||
* Record the index of the first uninitialized
|
||||
* arena, in case all extant arenas are in use.
|
||||
*
|
||||
* NB: It is possible for there to be
|
||||
* discontinuities in terms of initialized
|
||||
* versus uninitialized arenas, due to the
|
||||
* "thread.arena" mallctl.
|
||||
*/
|
||||
first_null = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (arenas[choose] == 0 || first_null == narenas) {
|
||||
/*
|
||||
* Use an unloaded arena, or the least loaded arena if
|
||||
* all arenas are already initialized.
|
||||
*/
|
||||
ret = arenas[choose];
|
||||
} else {
|
||||
/* Initialize a new arena. */
|
||||
ret = arenas_extend(first_null);
|
||||
}
|
||||
ret->nthreads++;
|
||||
malloc_mutex_unlock(&arenas_lock);
|
||||
} else
|
||||
} else {
|
||||
ret = arenas[0];
|
||||
malloc_mutex_lock(&arenas_lock);
|
||||
ret->nthreads++;
|
||||
malloc_mutex_unlock(&arenas_lock);
|
||||
}
|
||||
|
||||
ARENA_SET(ret);
|
||||
|
||||
@@ -213,6 +258,28 @@ stats_print_atexit(void)
|
||||
JEMALLOC_P(malloc_stats_print)(NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
#if (defined(JEMALLOC_STATS) && defined(NO_TLS))
|
||||
thread_allocated_t *
|
||||
thread_allocated_get_hard(void)
|
||||
{
|
||||
thread_allocated_t *thread_allocated = (thread_allocated_t *)
|
||||
imalloc(sizeof(thread_allocated_t));
|
||||
if (thread_allocated == NULL) {
|
||||
static thread_allocated_t static_thread_allocated = {0, 0};
|
||||
malloc_write("<jemalloc>: Error allocating TSD;"
|
||||
" mallctl(\"thread.{de,}allocated[p]\", ...)"
|
||||
" will be inaccurate\n");
|
||||
if (opt_abort)
|
||||
abort();
|
||||
return (&static_thread_allocated);
|
||||
}
|
||||
pthread_setspecific(thread_allocated_tsd, thread_allocated);
|
||||
thread_allocated->allocated = 0;
|
||||
thread_allocated->deallocated = 0;
|
||||
return (thread_allocated);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* End miscellaneous support functions.
|
||||
*/
|
||||
@@ -237,6 +304,16 @@ malloc_ncpus(void)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static void
|
||||
arenas_cleanup(void *arg)
|
||||
{
|
||||
arena_t *arena = (arena_t *)arg;
|
||||
|
||||
malloc_mutex_lock(&arenas_lock);
|
||||
arena->nthreads--;
|
||||
malloc_mutex_unlock(&arenas_lock);
|
||||
}
|
||||
|
||||
#if (defined(JEMALLOC_STATS) && defined(NO_TLS))
|
||||
static void
|
||||
thread_allocated_cleanup(void *arg)
|
||||
@@ -421,8 +498,8 @@ malloc_conf_init(void)
|
||||
if ((opts = getenv(envname)) != NULL) {
|
||||
/*
|
||||
* Do nothing; opts is already initialized to
|
||||
* the value of the JEMALLOC_OPTIONS
|
||||
* environment variable.
|
||||
* the value of the MALLOC_CONF environment
|
||||
* variable.
|
||||
*/
|
||||
} else {
|
||||
/* No configuration specified. */
|
||||
@@ -671,7 +748,10 @@ malloc_init_hard(void)
|
||||
}
|
||||
|
||||
#ifdef JEMALLOC_TCACHE
|
||||
tcache_boot();
|
||||
if (tcache_boot()) {
|
||||
malloc_mutex_unlock(&init_lock);
|
||||
return (true);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (huge_boot()) {
|
||||
@@ -712,8 +792,15 @@ malloc_init_hard(void)
|
||||
* threaded mode.
|
||||
*/
|
||||
ARENA_SET(arenas[0]);
|
||||
arenas[0]->nthreads++;
|
||||
|
||||
malloc_mutex_init(&arenas_lock);
|
||||
if (malloc_mutex_init(&arenas_lock))
|
||||
return (true);
|
||||
|
||||
if (pthread_key_create(&arenas_tsd, arenas_cleanup) != 0) {
|
||||
malloc_mutex_unlock(&init_lock);
|
||||
return (true);
|
||||
}
|
||||
|
||||
#ifdef JEMALLOC_PROF
|
||||
if (prof_boot2()) {
|
||||
@@ -753,15 +840,6 @@ malloc_init_hard(void)
|
||||
malloc_write(")\n");
|
||||
}
|
||||
|
||||
next_arena = (narenas > 0) ? 1 : 0;
|
||||
|
||||
#ifdef NO_TLS
|
||||
if (pthread_key_create(&arenas_tsd, NULL) != 0) {
|
||||
malloc_mutex_unlock(&init_lock);
|
||||
return (true);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Allocate and initialize arenas. */
|
||||
arenas = (arena_t **)base_alloc(sizeof(arena_t *) * narenas);
|
||||
if (arenas == NULL) {
|
||||
@@ -793,7 +871,6 @@ malloc_init_hard(void)
|
||||
return (false);
|
||||
}
|
||||
|
||||
|
||||
#ifdef JEMALLOC_ZONE
|
||||
JEMALLOC_ATTR(constructor)
|
||||
void
|
||||
@@ -916,14 +993,12 @@ int
|
||||
JEMALLOC_P(posix_memalign)(void **memptr, size_t alignment, size_t size)
|
||||
{
|
||||
int ret;
|
||||
void *result;
|
||||
#if (defined(JEMALLOC_PROF) || defined(JEMALLOC_STATS))
|
||||
size_t usize
|
||||
# ifdef JEMALLOC_CC_SILENCE
|
||||
#ifdef JEMALLOC_CC_SILENCE
|
||||
= 0
|
||||
# endif
|
||||
;
|
||||
#endif
|
||||
;
|
||||
void *result;
|
||||
#ifdef JEMALLOC_PROF
|
||||
prof_thr_cnt_t *cnt
|
||||
# ifdef JEMALLOC_CC_SILENCE
|
||||
@@ -973,34 +1048,37 @@ JEMALLOC_P(posix_memalign)(void **memptr, size_t alignment, size_t size)
|
||||
goto RETURN;
|
||||
}
|
||||
|
||||
usize = sa2u(size, alignment, NULL);
|
||||
if (usize == 0) {
|
||||
result = NULL;
|
||||
ret = ENOMEM;
|
||||
goto RETURN;
|
||||
}
|
||||
|
||||
#ifdef JEMALLOC_PROF
|
||||
if (opt_prof) {
|
||||
usize = sa2u(size, alignment, NULL);
|
||||
if ((cnt = prof_alloc_prep(usize)) == NULL) {
|
||||
result = NULL;
|
||||
ret = EINVAL;
|
||||
} else {
|
||||
if (prof_promote && (uintptr_t)cnt !=
|
||||
(uintptr_t)1U && usize <= small_maxclass) {
|
||||
result = ipalloc(small_maxclass+1,
|
||||
alignment, false);
|
||||
assert(sa2u(small_maxclass+1,
|
||||
alignment, NULL) != 0);
|
||||
result = ipalloc(sa2u(small_maxclass+1,
|
||||
alignment, NULL), alignment, false);
|
||||
if (result != NULL) {
|
||||
arena_prof_promoted(result,
|
||||
usize);
|
||||
}
|
||||
} else {
|
||||
result = ipalloc(size, alignment,
|
||||
result = ipalloc(usize, alignment,
|
||||
false);
|
||||
}
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
#ifdef JEMALLOC_STATS
|
||||
usize = sa2u(size, alignment, NULL);
|
||||
#endif
|
||||
result = ipalloc(size, alignment, false);
|
||||
}
|
||||
result = ipalloc(usize, alignment, false);
|
||||
}
|
||||
|
||||
if (result == NULL) {
|
||||
@@ -1454,15 +1532,18 @@ JEMALLOC_P(mallctlbymib)(const size_t *mib, size_t miblen, void *oldp,
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void *
|
||||
iallocm(size_t size, size_t alignment, bool zero)
|
||||
iallocm(size_t usize, size_t alignment, bool zero)
|
||||
{
|
||||
|
||||
assert(usize == ((alignment == 0) ? s2u(usize) : sa2u(usize, alignment,
|
||||
NULL)));
|
||||
|
||||
if (alignment != 0)
|
||||
return (ipalloc(size, alignment, zero));
|
||||
return (ipalloc(usize, alignment, zero));
|
||||
else if (zero)
|
||||
return (icalloc(size));
|
||||
return (icalloc(usize));
|
||||
else
|
||||
return (imalloc(size));
|
||||
return (imalloc(usize));
|
||||
}
|
||||
|
||||
JEMALLOC_ATTR(nonnull(1))
|
||||
@@ -1485,20 +1566,27 @@ JEMALLOC_P(allocm)(void **ptr, size_t *rsize, size_t size, int flags)
|
||||
if (malloc_init())
|
||||
goto OOM;
|
||||
|
||||
usize = (alignment == 0) ? s2u(size) : sa2u(size, alignment,
|
||||
NULL);
|
||||
if (usize == 0)
|
||||
goto OOM;
|
||||
|
||||
#ifdef JEMALLOC_PROF
|
||||
if (opt_prof) {
|
||||
usize = (alignment == 0) ? s2u(size) : sa2u(size, alignment,
|
||||
NULL);
|
||||
if ((cnt = prof_alloc_prep(usize)) == NULL)
|
||||
goto OOM;
|
||||
if (prof_promote && (uintptr_t)cnt != (uintptr_t)1U && usize <=
|
||||
small_maxclass) {
|
||||
p = iallocm(small_maxclass+1, alignment, zero);
|
||||
size_t usize_promoted = (alignment == 0) ?
|
||||
s2u(small_maxclass+1) : sa2u(small_maxclass+1,
|
||||
alignment, NULL);
|
||||
assert(usize_promoted != 0);
|
||||
p = iallocm(usize_promoted, alignment, zero);
|
||||
if (p == NULL)
|
||||
goto OOM;
|
||||
arena_prof_promoted(p, usize);
|
||||
} else {
|
||||
p = iallocm(size, alignment, zero);
|
||||
p = iallocm(usize, alignment, zero);
|
||||
if (p == NULL)
|
||||
goto OOM;
|
||||
}
|
||||
@@ -1508,15 +1596,13 @@ JEMALLOC_P(allocm)(void **ptr, size_t *rsize, size_t size, int flags)
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
p = iallocm(size, alignment, zero);
|
||||
p = iallocm(usize, alignment, zero);
|
||||
if (p == NULL)
|
||||
goto OOM;
|
||||
#ifndef JEMALLOC_STATS
|
||||
if (rsize != NULL)
|
||||
#endif
|
||||
{
|
||||
usize = (alignment == 0) ? s2u(size) : sa2u(size,
|
||||
alignment, NULL);
|
||||
#ifdef JEMALLOC_STATS
|
||||
if (rsize != NULL)
|
||||
#endif
|
||||
@@ -1600,6 +1686,8 @@ JEMALLOC_P(rallocm)(void **ptr, size_t *rsize, size_t size, size_t extra,
|
||||
usize = isalloc(q);
|
||||
}
|
||||
prof_realloc(q, usize, cnt, old_size, old_ctx);
|
||||
if (rsize != NULL)
|
||||
*rsize = usize;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#define MB_C_
|
||||
#define JEMALLOC_MB_C_
|
||||
#include "jemalloc/internal/jemalloc_internal.h"
|
||||
|
||||
@@ -55,6 +55,9 @@ pthread_create(pthread_t *__restrict thread,
|
||||
bool
|
||||
malloc_mutex_init(malloc_mutex_t *mutex)
|
||||
{
|
||||
#ifdef JEMALLOC_OSSPIN
|
||||
*mutex = 0;
|
||||
#else
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
if (pthread_mutexattr_init(&attr) != 0)
|
||||
@@ -70,6 +73,7 @@ malloc_mutex_init(malloc_mutex_t *mutex)
|
||||
}
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
|
||||
#endif
|
||||
return (false);
|
||||
}
|
||||
|
||||
@@ -77,8 +81,10 @@ 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
|
||||
}
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
#ifdef JEMALLOC_PROF
|
||||
/******************************************************************************/
|
||||
|
||||
#ifdef JEMALLOC_PROF_LIBGCC
|
||||
#include <unwind.h>
|
||||
#endif
|
||||
|
||||
#ifdef JEMALLOC_PROF_LIBUNWIND
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include <libunwind.h>
|
||||
#endif
|
||||
|
||||
#ifdef JEMALLOC_PROF_LIBGCC
|
||||
#include <unwind.h>
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
/* Data. */
|
||||
|
||||
@@ -169,39 +169,7 @@ prof_leave(void)
|
||||
prof_gdump();
|
||||
}
|
||||
|
||||
#ifdef JEMALLOC_PROF_LIBGCC
|
||||
static _Unwind_Reason_Code
|
||||
prof_unwind_init_callback(struct _Unwind_Context *context, void *arg)
|
||||
{
|
||||
|
||||
return (_URC_NO_REASON);
|
||||
}
|
||||
|
||||
static _Unwind_Reason_Code
|
||||
prof_unwind_callback(struct _Unwind_Context *context, void *arg)
|
||||
{
|
||||
prof_unwind_data_t *data = (prof_unwind_data_t *)arg;
|
||||
|
||||
if (data->nignore > 0)
|
||||
data->nignore--;
|
||||
else {
|
||||
data->bt->vec[data->bt->len] = (void *)_Unwind_GetIP(context);
|
||||
data->bt->len++;
|
||||
if (data->bt->len == data->max)
|
||||
return (_URC_END_OF_STACK);
|
||||
}
|
||||
|
||||
return (_URC_NO_REASON);
|
||||
}
|
||||
|
||||
void
|
||||
prof_backtrace(prof_bt_t *bt, unsigned nignore, unsigned max)
|
||||
{
|
||||
prof_unwind_data_t data = {bt, nignore, max};
|
||||
|
||||
_Unwind_Backtrace(prof_unwind_callback, &data);
|
||||
}
|
||||
#elif defined(JEMALLOC_PROF_LIBUNWIND)
|
||||
#ifdef JEMALLOC_PROF_LIBUNWIND
|
||||
void
|
||||
prof_backtrace(prof_bt_t *bt, unsigned nignore, unsigned max)
|
||||
{
|
||||
@@ -236,7 +204,41 @@ prof_backtrace(prof_bt_t *bt, unsigned nignore, unsigned max)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
#ifdef JEMALLOC_PROF_LIBGCC
|
||||
static _Unwind_Reason_Code
|
||||
prof_unwind_init_callback(struct _Unwind_Context *context, void *arg)
|
||||
{
|
||||
|
||||
return (_URC_NO_REASON);
|
||||
}
|
||||
|
||||
static _Unwind_Reason_Code
|
||||
prof_unwind_callback(struct _Unwind_Context *context, void *arg)
|
||||
{
|
||||
prof_unwind_data_t *data = (prof_unwind_data_t *)arg;
|
||||
|
||||
if (data->nignore > 0)
|
||||
data->nignore--;
|
||||
else {
|
||||
data->bt->vec[data->bt->len] = (void *)_Unwind_GetIP(context);
|
||||
data->bt->len++;
|
||||
if (data->bt->len == data->max)
|
||||
return (_URC_END_OF_STACK);
|
||||
}
|
||||
|
||||
return (_URC_NO_REASON);
|
||||
}
|
||||
|
||||
void
|
||||
prof_backtrace(prof_bt_t *bt, unsigned nignore, unsigned max)
|
||||
{
|
||||
prof_unwind_data_t data = {bt, nignore, max};
|
||||
|
||||
_Unwind_Backtrace(prof_unwind_callback, &data);
|
||||
}
|
||||
#endif
|
||||
#ifdef JEMALLOC_PROF_GCC
|
||||
void
|
||||
prof_backtrace(prof_bt_t *bt, unsigned nignore, unsigned max)
|
||||
{
|
||||
@@ -255,6 +257,7 @@ prof_backtrace(prof_bt_t *bt, unsigned nignore, unsigned max)
|
||||
} else \
|
||||
return;
|
||||
|
||||
assert(nignore <= 3);
|
||||
assert(max <= (1U << opt_lg_prof_bt_max));
|
||||
|
||||
BT_FRAME(0)
|
||||
@@ -398,7 +401,7 @@ prof_backtrace(prof_bt_t *bt, unsigned nignore, unsigned max)
|
||||
BT_FRAME(126)
|
||||
BT_FRAME(127)
|
||||
|
||||
/* Extras to compensate for NIGNORE. */
|
||||
/* Extras to compensate for nignore. */
|
||||
BT_FRAME(128)
|
||||
BT_FRAME(129)
|
||||
BT_FRAME(130)
|
||||
@@ -431,6 +434,7 @@ prof_lookup(prof_bt_t *bt)
|
||||
prof_ctx_t *p;
|
||||
void *v;
|
||||
} ctx;
|
||||
bool new_ctx;
|
||||
|
||||
/*
|
||||
* This thread's cache lacks bt. Look for it in the global
|
||||
@@ -467,12 +471,14 @@ prof_lookup(prof_bt_t *bt)
|
||||
idalloc(ctx.v);
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Acquire ctx's lock before releasing bt2ctx_mtx, in order to
|
||||
* avoid a race condition with prof_ctx_destroy().
|
||||
*/
|
||||
malloc_mutex_lock(&ctx.p->lock);
|
||||
/*
|
||||
* Artificially raise curobjs, in order to avoid a race
|
||||
* condition with prof_ctx_merge()/prof_ctx_destroy().
|
||||
*/
|
||||
ctx.p->cnt_merged.curobjs++;
|
||||
new_ctx = true;
|
||||
} else
|
||||
new_ctx = false;
|
||||
prof_leave();
|
||||
|
||||
/* Link a prof_thd_cnt_t into ctx for this thread. */
|
||||
@@ -496,8 +502,14 @@ prof_lookup(prof_bt_t *bt)
|
||||
opt_lg_prof_tcmax));
|
||||
/* Allocate and partially initialize a new cnt. */
|
||||
ret.v = imalloc(sizeof(prof_thr_cnt_t));
|
||||
if (ret.p == NULL)
|
||||
if (ret.p == NULL) {
|
||||
if (new_ctx) {
|
||||
malloc_mutex_lock(&ctx.p->lock);
|
||||
ctx.p->cnt_merged.curobjs--;
|
||||
malloc_mutex_unlock(&ctx.p->lock);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
ql_elm_new(ret.p, cnts_link);
|
||||
ql_elm_new(ret.p, lru_link);
|
||||
}
|
||||
@@ -506,11 +518,19 @@ prof_lookup(prof_bt_t *bt)
|
||||
ret.p->epoch = 0;
|
||||
memset(&ret.p->cnts, 0, sizeof(prof_cnt_t));
|
||||
if (ckh_insert(&prof_tdata->bt2cnt, btkey.v, ret.v)) {
|
||||
if (new_ctx) {
|
||||
malloc_mutex_lock(&ctx.p->lock);
|
||||
ctx.p->cnt_merged.curobjs--;
|
||||
malloc_mutex_unlock(&ctx.p->lock);
|
||||
}
|
||||
idalloc(ret.v);
|
||||
return (NULL);
|
||||
}
|
||||
ql_head_insert(&prof_tdata->lru_ql, ret.p, lru_link);
|
||||
malloc_mutex_lock(&ctx.p->lock);
|
||||
ql_tail_insert(&ctx.p->cnts_ql, ret.p, cnts_link);
|
||||
if (new_ctx)
|
||||
ctx.p->cnt_merged.curobjs--;
|
||||
malloc_mutex_unlock(&ctx.p->lock);
|
||||
} else {
|
||||
/* Move ret to the front of the LRU. */
|
||||
@@ -625,11 +645,14 @@ prof_ctx_destroy(prof_ctx_t *ctx)
|
||||
/*
|
||||
* Check that ctx is still unused by any thread cache before destroying
|
||||
* it. prof_lookup() interlocks bt2ctx_mtx and ctx->lock in order to
|
||||
* avoid a race condition with this function.
|
||||
* avoid a race condition with this function, and prof_ctx_merge()
|
||||
* artificially raises ctx->cnt_merged.curobjs in order to avoid a race
|
||||
* between the main body of prof_ctx_merge() and entry into this
|
||||
* function.
|
||||
*/
|
||||
prof_enter();
|
||||
malloc_mutex_lock(&ctx->lock);
|
||||
if (ql_first(&ctx->cnts_ql) == NULL && ctx->cnt_merged.curobjs == 0) {
|
||||
if (ql_first(&ctx->cnts_ql) == NULL && ctx->cnt_merged.curobjs == 1) {
|
||||
assert(ctx->cnt_merged.curbytes == 0);
|
||||
assert(ctx->cnt_merged.accumobjs == 0);
|
||||
assert(ctx->cnt_merged.accumbytes == 0);
|
||||
@@ -642,6 +665,8 @@ prof_ctx_destroy(prof_ctx_t *ctx)
|
||||
malloc_mutex_destroy(&ctx->lock);
|
||||
idalloc(ctx);
|
||||
} else {
|
||||
/* Compensate for increment in prof_ctx_merge(). */
|
||||
ctx->cnt_merged.curobjs--;
|
||||
malloc_mutex_unlock(&ctx->lock);
|
||||
prof_leave();
|
||||
}
|
||||
@@ -660,9 +685,23 @@ prof_ctx_merge(prof_ctx_t *ctx, prof_thr_cnt_t *cnt)
|
||||
ctx->cnt_merged.accumbytes += cnt->cnts.accumbytes;
|
||||
ql_remove(&ctx->cnts_ql, cnt, cnts_link);
|
||||
if (opt_prof_accum == false && ql_first(&ctx->cnts_ql) == NULL &&
|
||||
ctx->cnt_merged.curobjs == 0)
|
||||
ctx->cnt_merged.curobjs == 0) {
|
||||
/*
|
||||
* Artificially raise ctx->cnt_merged.curobjs in order to keep
|
||||
* another thread from winning the race to destroy ctx while
|
||||
* this one has ctx->lock dropped. Without this, it would be
|
||||
* possible for another thread to:
|
||||
*
|
||||
* 1) Sample an allocation associated with ctx.
|
||||
* 2) Deallocate the sampled object.
|
||||
* 3) Successfully prof_ctx_destroy(ctx).
|
||||
*
|
||||
* The result would be that ctx no longer exists by the time
|
||||
* this thread accesses it in prof_ctx_destroy().
|
||||
*/
|
||||
ctx->cnt_merged.curobjs++;
|
||||
destroy = true;
|
||||
else
|
||||
} else
|
||||
destroy = false;
|
||||
malloc_mutex_unlock(&ctx->lock);
|
||||
if (destroy)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#define RTREE_C_
|
||||
#define JEMALLOC_RTREE_C_
|
||||
#include "jemalloc/internal/jemalloc_internal.h"
|
||||
|
||||
rtree_t *
|
||||
@@ -20,7 +20,10 @@ rtree_new(unsigned bits)
|
||||
memset(ret, 0, offsetof(rtree_t, level2bits) + (sizeof(unsigned) *
|
||||
height));
|
||||
|
||||
malloc_mutex_init(&ret->mutex);
|
||||
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;
|
||||
|
||||
@@ -39,6 +39,10 @@
|
||||
|
||||
bool opt_stats_print = false;
|
||||
|
||||
#ifdef JEMALLOC_STATS
|
||||
size_t stats_cactive = 0;
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
/* Function prototypes for non-inline static functions. */
|
||||
|
||||
@@ -319,6 +323,7 @@ static void
|
||||
stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque,
|
||||
unsigned i)
|
||||
{
|
||||
unsigned nthreads;
|
||||
size_t pagesize, pactive, pdirty, mapped;
|
||||
uint64_t npurge, nmadvise, purged;
|
||||
size_t small_allocated;
|
||||
@@ -328,6 +333,9 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque,
|
||||
|
||||
CTL_GET("arenas.pagesize", &pagesize, size_t);
|
||||
|
||||
CTL_I_GET("stats.arenas.0.nthreads", &nthreads, unsigned);
|
||||
malloc_cprintf(write_cb, cbopaque,
|
||||
"assigned threads: %u\n", nthreads);
|
||||
CTL_I_GET("stats.arenas.0.pactive", &pactive, size_t);
|
||||
CTL_I_GET("stats.arenas.0.pdirty", &pdirty, size_t);
|
||||
CTL_I_GET("stats.arenas.0.npurge", &npurge, uint64_t);
|
||||
@@ -669,21 +677,26 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
|
||||
#ifdef JEMALLOC_STATS
|
||||
{
|
||||
int err;
|
||||
size_t ssz;
|
||||
size_t sszp, ssz;
|
||||
size_t *cactive;
|
||||
size_t allocated, active, mapped;
|
||||
size_t chunks_current, chunks_high, swap_avail;
|
||||
uint64_t chunks_total;
|
||||
size_t huge_allocated;
|
||||
uint64_t huge_nmalloc, huge_ndalloc;
|
||||
|
||||
sszp = sizeof(size_t *);
|
||||
ssz = sizeof(size_t);
|
||||
|
||||
CTL_GET("stats.cactive", &cactive, size_t *);
|
||||
CTL_GET("stats.allocated", &allocated, size_t);
|
||||
CTL_GET("stats.active", &active, size_t);
|
||||
CTL_GET("stats.mapped", &mapped, size_t);
|
||||
malloc_cprintf(write_cb, cbopaque,
|
||||
"Allocated: %zu, active: %zu, mapped: %zu\n", allocated,
|
||||
active, mapped);
|
||||
"Allocated: %zu, active: %zu, mapped: %zu\n",
|
||||
allocated, active, mapped);
|
||||
malloc_cprintf(write_cb, cbopaque,
|
||||
"Current active ceiling: %zu\n", atomic_read_z(cactive));
|
||||
|
||||
/* Print chunk stats. */
|
||||
CTL_GET("stats.chunks.total", &chunks_total, uint64_t);
|
||||
|
||||
@@ -8,6 +8,9 @@ bool opt_tcache = true;
|
||||
ssize_t opt_lg_tcache_max = LG_TCACHE_MAXCLASS_DEFAULT;
|
||||
ssize_t opt_lg_tcache_gc_sweep = LG_TCACHE_GC_SWEEP_DEFAULT;
|
||||
|
||||
tcache_bin_info_t *tcache_bin_info;
|
||||
static unsigned stack_nelms; /* Total stack elms per tcache. */
|
||||
|
||||
/* Map of thread-specific caches. */
|
||||
#ifndef NO_TLS
|
||||
__thread tcache_t *tcache_tls JEMALLOC_ATTR(tls_model("initial-exec"));
|
||||
@@ -55,18 +58,19 @@ tcache_bin_flush_small(tcache_bin_t *tbin, size_t binind, unsigned rem
|
||||
#endif
|
||||
)
|
||||
{
|
||||
void *flush, *deferred, *ptr;
|
||||
void *ptr;
|
||||
unsigned i, nflush, ndeferred;
|
||||
bool first_pass;
|
||||
#ifdef JEMALLOC_STATS
|
||||
bool merged_stats = false;
|
||||
#endif
|
||||
|
||||
assert(binind < nbins);
|
||||
assert(rem <= tbin->ncached);
|
||||
assert(tbin->ncached > 0 || tbin->avail == NULL);
|
||||
|
||||
for (flush = tbin->avail, nflush = tbin->ncached - rem, first_pass =
|
||||
true; flush != NULL; flush = deferred, nflush = ndeferred) {
|
||||
for (nflush = tbin->ncached - rem; nflush > 0; nflush = ndeferred) {
|
||||
/* Lock the arena bin associated with the first object. */
|
||||
arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(flush);
|
||||
arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(
|
||||
tbin->avail[0]);
|
||||
arena_t *arena = chunk->arena;
|
||||
arena_bin_t *bin = &arena->bins[binind];
|
||||
|
||||
@@ -82,17 +86,17 @@ tcache_bin_flush_small(tcache_bin_t *tbin, size_t binind, unsigned rem
|
||||
malloc_mutex_lock(&bin->lock);
|
||||
#ifdef JEMALLOC_STATS
|
||||
if (arena == tcache->arena) {
|
||||
assert(merged_stats == false);
|
||||
merged_stats = true;
|
||||
bin->stats.nflushes++;
|
||||
bin->stats.nrequests += tbin->tstats.nrequests;
|
||||
tbin->tstats.nrequests = 0;
|
||||
}
|
||||
#endif
|
||||
deferred = NULL;
|
||||
ndeferred = 0;
|
||||
for (i = 0; i < nflush; i++) {
|
||||
ptr = flush;
|
||||
ptr = tbin->avail[i];
|
||||
assert(ptr != NULL);
|
||||
flush = *(void **)ptr;
|
||||
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
||||
if (chunk->arena == arena) {
|
||||
size_t pageind = ((uintptr_t)ptr -
|
||||
@@ -107,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
|
||||
* handled in a future pass.
|
||||
*/
|
||||
*(void **)ptr = deferred;
|
||||
deferred = ptr;
|
||||
tbin->avail[ndeferred] = ptr;
|
||||
ndeferred++;
|
||||
}
|
||||
}
|
||||
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;
|
||||
if (tbin->ncached < tbin->low_water)
|
||||
if ((int)tbin->ncached < tbin->low_water)
|
||||
tbin->low_water = tbin->ncached;
|
||||
}
|
||||
|
||||
@@ -132,18 +146,19 @@ tcache_bin_flush_large(tcache_bin_t *tbin, size_t binind, unsigned rem
|
||||
#endif
|
||||
)
|
||||
{
|
||||
void *flush, *deferred, *ptr;
|
||||
void *ptr;
|
||||
unsigned i, nflush, ndeferred;
|
||||
bool first_pass;
|
||||
#ifdef JEMALLOC_STATS
|
||||
bool merged_stats = false;
|
||||
#endif
|
||||
|
||||
assert(binind < nhbins);
|
||||
assert(rem <= tbin->ncached);
|
||||
assert(tbin->ncached > 0 || tbin->avail == NULL);
|
||||
|
||||
for (flush = tbin->avail, nflush = tbin->ncached - rem, first_pass =
|
||||
true; flush != NULL; flush = deferred, nflush = ndeferred) {
|
||||
for (nflush = tbin->ncached - rem; nflush > 0; nflush = ndeferred) {
|
||||
/* Lock the arena associated with the first object. */
|
||||
arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(flush);
|
||||
arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(
|
||||
tbin->avail[0]);
|
||||
arena_t *arena = chunk->arena;
|
||||
|
||||
malloc_mutex_lock(&arena->lock);
|
||||
@@ -155,6 +170,7 @@ tcache_bin_flush_large(tcache_bin_t *tbin, size_t binind, unsigned rem
|
||||
tcache->prof_accumbytes = 0;
|
||||
#endif
|
||||
#ifdef JEMALLOC_STATS
|
||||
merged_stats = true;
|
||||
arena->stats.nrequests_large += tbin->tstats.nrequests;
|
||||
arena->stats.lstats[binind - nbins].nrequests +=
|
||||
tbin->tstats.nrequests;
|
||||
@@ -163,12 +179,10 @@ tcache_bin_flush_large(tcache_bin_t *tbin, size_t binind, unsigned rem
|
||||
#if (defined(JEMALLOC_PROF) || defined(JEMALLOC_STATS))
|
||||
}
|
||||
#endif
|
||||
deferred = NULL;
|
||||
ndeferred = 0;
|
||||
for (i = 0; i < nflush; i++) {
|
||||
ptr = flush;
|
||||
ptr = tbin->avail[i];
|
||||
assert(ptr != NULL);
|
||||
flush = *(void **)ptr;
|
||||
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
|
||||
if (chunk->arena == arena)
|
||||
arena_dalloc_large(arena, chunk, ptr);
|
||||
@@ -179,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
|
||||
* in a future pass.
|
||||
*/
|
||||
*(void **)ptr = deferred;
|
||||
deferred = ptr;
|
||||
tbin->avail[ndeferred] = ptr;
|
||||
ndeferred++;
|
||||
}
|
||||
}
|
||||
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;
|
||||
if (tbin->ncached < tbin->low_water)
|
||||
if ((int)tbin->ncached < tbin->low_water)
|
||||
tbin->low_water = tbin->ncached;
|
||||
}
|
||||
|
||||
@@ -201,10 +226,14 @@ tcache_t *
|
||||
tcache_create(arena_t *arena)
|
||||
{
|
||||
tcache_t *tcache;
|
||||
size_t size;
|
||||
size_t size, stack_offset;
|
||||
unsigned i;
|
||||
|
||||
size = offsetof(tcache_t, tbins) + (sizeof(tcache_bin_t) * nhbins);
|
||||
/* Naturally align the pointer stacks. */
|
||||
size = PTR_CEILING(size);
|
||||
stack_offset = size;
|
||||
size += stack_nelms * sizeof(void *);
|
||||
/*
|
||||
* Round up to the nearest multiple of the cacheline size, in order to
|
||||
* avoid the possibility of false cacheline sharing.
|
||||
@@ -217,6 +246,8 @@ tcache_create(arena_t *arena)
|
||||
|
||||
if (size <= small_maxclass)
|
||||
tcache = (tcache_t *)arena_malloc_small(arena, size, true);
|
||||
else if (size <= tcache_maxclass)
|
||||
tcache = (tcache_t *)arena_malloc_large(arena, size, true);
|
||||
else
|
||||
tcache = (tcache_t *)icalloc(size);
|
||||
|
||||
@@ -233,15 +264,12 @@ tcache_create(arena_t *arena)
|
||||
|
||||
tcache->arena = arena;
|
||||
assert((TCACHE_NSLOTS_SMALL_MAX & 1U) == 0);
|
||||
for (i = 0; i < nbins; i++) {
|
||||
if ((arena->bins[i].nregs << 1) <= TCACHE_NSLOTS_SMALL_MAX) {
|
||||
tcache->tbins[i].ncached_max = (arena->bins[i].nregs <<
|
||||
1);
|
||||
} else
|
||||
tcache->tbins[i].ncached_max = TCACHE_NSLOTS_SMALL_MAX;
|
||||
for (i = 0; i < nhbins; i++) {
|
||||
tcache->tbins[i].lg_fill_div = 1;
|
||||
tcache->tbins[i].avail = (void **)((uintptr_t)tcache +
|
||||
(uintptr_t)stack_offset);
|
||||
stack_offset += tcache_bin_info[i].ncached_max * sizeof(void *);
|
||||
}
|
||||
for (; i < nhbins; i++)
|
||||
tcache->tbins[i].ncached_max = TCACHE_NSLOTS_LARGE;
|
||||
|
||||
TCACHE_SET(tcache);
|
||||
|
||||
@@ -252,6 +280,7 @@ void
|
||||
tcache_destroy(tcache_t *tcache)
|
||||
{
|
||||
unsigned i;
|
||||
size_t tcache_size;
|
||||
|
||||
#ifdef JEMALLOC_STATS
|
||||
/* Unlink from list of extant tcaches. */
|
||||
@@ -308,7 +337,8 @@ tcache_destroy(tcache_t *tcache)
|
||||
}
|
||||
#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_t *arena = chunk->arena;
|
||||
size_t pageind = ((uintptr_t)tcache - (uintptr_t)chunk) >>
|
||||
@@ -322,6 +352,13 @@ tcache_destroy(tcache_t *tcache)
|
||||
malloc_mutex_lock(&bin->lock);
|
||||
arena_dalloc_bin(arena, chunk, tcache, mapelm);
|
||||
malloc_mutex_unlock(&bin->lock);
|
||||
} else if (tcache_size <= tcache_maxclass) {
|
||||
arena_chunk_t *chunk = CHUNK_ADDR2BASE(tcache);
|
||||
arena_t *arena = chunk->arena;
|
||||
|
||||
malloc_mutex_lock(&arena->lock);
|
||||
arena_dalloc_large(arena, chunk, tcache);
|
||||
malloc_mutex_unlock(&arena->lock);
|
||||
} else
|
||||
idalloc(tcache);
|
||||
}
|
||||
@@ -378,11 +415,13 @@ tcache_stats_merge(tcache_t *tcache, arena_t *arena)
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
bool
|
||||
tcache_boot(void)
|
||||
{
|
||||
|
||||
if (opt_tcache) {
|
||||
unsigned i;
|
||||
|
||||
/*
|
||||
* If necessary, clamp opt_lg_tcache_max, now that
|
||||
* small_maxclass and arena_maxclass are known.
|
||||
@@ -397,6 +436,28 @@ tcache_boot(void)
|
||||
|
||||
nhbins = nbins + (tcache_maxclass >> PAGE_SHIFT);
|
||||
|
||||
/* Initialize tcache_bin_info. */
|
||||
tcache_bin_info = (tcache_bin_info_t *)base_alloc(nhbins *
|
||||
sizeof(tcache_bin_info_t));
|
||||
if (tcache_bin_info == NULL)
|
||||
return (true);
|
||||
stack_nelms = 0;
|
||||
for (i = 0; i < nbins; i++) {
|
||||
if ((arena_bin_info[i].nregs << 1) <=
|
||||
TCACHE_NSLOTS_SMALL_MAX) {
|
||||
tcache_bin_info[i].ncached_max =
|
||||
(arena_bin_info[i].nregs << 1);
|
||||
} else {
|
||||
tcache_bin_info[i].ncached_max =
|
||||
TCACHE_NSLOTS_SMALL_MAX;
|
||||
}
|
||||
stack_nelms += tcache_bin_info[i].ncached_max;
|
||||
}
|
||||
for (; i < nhbins; i++) {
|
||||
tcache_bin_info[i].ncached_max = TCACHE_NSLOTS_LARGE;
|
||||
stack_nelms += tcache_bin_info[i].ncached_max;
|
||||
}
|
||||
|
||||
/* Compute incremental GC event threshold. */
|
||||
if (opt_lg_tcache_gc_sweep >= 0) {
|
||||
tcache_gc_incr = ((1U << opt_lg_tcache_gc_sweep) /
|
||||
@@ -412,6 +473,8 @@ tcache_boot(void)
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
return (false);
|
||||
}
|
||||
/******************************************************************************/
|
||||
#endif /* JEMALLOC_TCACHE */
|
||||
|
||||
@@ -16,6 +16,7 @@ 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);
|
||||
@@ -31,6 +32,20 @@ thread_start(void *arg)
|
||||
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,
|
||||
@@ -45,6 +60,20 @@ thread_start(void *arg)
|
||||
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) {
|
||||
@@ -54,6 +83,10 @@ thread_start(void *arg)
|
||||
|
||||
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);
|
||||
@@ -62,6 +95,10 @@ thread_start(void *arg)
|
||||
|
||||
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);
|
||||
|
||||
|
||||
157
jemalloc/test/bitmap.c
Normal file
157
jemalloc/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
jemalloc/test/bitmap.exp
Normal file
2
jemalloc/test/bitmap.exp
Normal file
@@ -0,0 +1,2 @@
|
||||
Test begin
|
||||
Test end
|
||||
67
jemalloc/test/mremap.c
Normal file
67
jemalloc/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
jemalloc/test/mremap.exp
Normal file
2
jemalloc/test/mremap.exp
Normal file
@@ -0,0 +1,2 @@
|
||||
Test begin
|
||||
Test end
|
||||
@@ -2,10 +2,13 @@
|
||||
#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)
|
||||
{
|
||||
@@ -29,6 +32,15 @@ thread_start(void *arg)
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -40,7 +52,8 @@ main(void)
|
||||
unsigned arena_ind;
|
||||
size_t size;
|
||||
int err;
|
||||
pthread_t thread;
|
||||
pthread_t threads[NTHREADS];
|
||||
unsigned i;
|
||||
|
||||
fprintf(stderr, "Test begin\n");
|
||||
|
||||
@@ -60,21 +73,18 @@ main(void)
|
||||
goto RETURN;
|
||||
}
|
||||
|
||||
if (pthread_create(&thread, 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++) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
pthread_join(thread, (void *)&ret);
|
||||
|
||||
if (pthread_create(&thread, NULL, thread_start, (void *)&arena_ind)
|
||||
!= 0) {
|
||||
fprintf(stderr, "%s(): Error in pthread_create()\n", __func__);
|
||||
ret = 1;
|
||||
goto RETURN;
|
||||
}
|
||||
pthread_join(thread, (void *)&ret);
|
||||
for (i = 0; i < NTHREADS; i++)
|
||||
pthread_join(threads[i], (void *)&ret);
|
||||
|
||||
RETURN:
|
||||
fprintf(stderr, "Test end\n");
|
||||
|
||||
Reference in New Issue
Block a user