mirror of
https://codeberg.org/redict/redict.git
synced 2025-01-22 08:08:53 -05:00
Merge pull request #9623 from yoav-steinberg/upgrade_jemalloc_5.2.1
Upgraded to jemalloc 5.2.1 from 5.1.0. Cherry picked all relevant fixes (by diffing our 5.1.0 to upstream 5.10 and finding relevant commits). Details of what was done: [cherry-picked]fd7d51c
2021-05-03 Resolve nonsense static analysis warnings (Oran Agra) [cherry-picked]448c435
2020-09-29 Fix compilation warnings in Lua and jemalloc dependencies (#7785) (YoongHM) [skipped - already in upstream]9216b96
2020-09-21 Fix compilation warning in jemalloc's malloc_vsnprintf (#7789) (YoongHM) [cherry-picked]88d71f4
2020-05-20 fix a rare active defrag edge case bug leading to stagnation (Oran Agra) [skipped - already in upstream]2fec7d9
2019-05-30 Jemalloc: Avoid blocking on background thread lock for stats. [cherry-picked]920158e
2018-07-11 Active defrag fixes for 32bit builds (again) (Oran Agra) [cherry-picked]e8099ca
2018-06-26 add defrag hint support into jemalloc 5 (Oran Agra) [re-done]4e729fc
2018-05-24 Generate configure for Jemalloc. (antirez) Additionally had to do this: 7727cc2 2021-10-10 Fix defrag to support sharded bins in arena (added in v5.2.1) (Yoav Steinberg) When reviewing please look at all except the first commit which is just replacing 5.1.0 with 5.2.1 sources. Also I think we should merge this without squashing to preserve the changes we did to to jemalloc.
This commit is contained in:
commit
c4b4b6c06b
2
deps/Makefile
vendored
2
deps/Makefile
vendored
@ -88,7 +88,7 @@ JEMALLOC_LDFLAGS= $(LDFLAGS)
|
|||||||
|
|
||||||
jemalloc: .make-prerequisites
|
jemalloc: .make-prerequisites
|
||||||
@printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR)
|
@printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR)
|
||||||
cd jemalloc && ./configure --with-version=5.1.0-0-g0 --with-lg-quantum=3 --with-jemalloc-prefix=je_ CFLAGS="$(JEMALLOC_CFLAGS)" LDFLAGS="$(JEMALLOC_LDFLAGS)"
|
cd jemalloc && ./configure --with-version=5.2.1-0-g0 --with-lg-quantum=3 --with-jemalloc-prefix=je_ CFLAGS="$(JEMALLOC_CFLAGS)" LDFLAGS="$(JEMALLOC_LDFLAGS)"
|
||||||
cd jemalloc && $(MAKE) CFLAGS="$(JEMALLOC_CFLAGS)" LDFLAGS="$(JEMALLOC_LDFLAGS)" lib/libjemalloc.a
|
cd jemalloc && $(MAKE) CFLAGS="$(JEMALLOC_CFLAGS)" LDFLAGS="$(JEMALLOC_LDFLAGS)" lib/libjemalloc.a
|
||||||
|
|
||||||
.PHONY: jemalloc
|
.PHONY: jemalloc
|
||||||
|
18
deps/README.md
vendored
18
deps/README.md
vendored
@ -41,6 +41,22 @@ the following additional steps:
|
|||||||
changed, otherwise you could just copy the old implementation if you are
|
changed, otherwise you could just copy the old implementation if you are
|
||||||
upgrading just to a similar version of Jemalloc.
|
upgrading just to a similar version of Jemalloc.
|
||||||
|
|
||||||
|
#### Updating/upgrading jemalloc
|
||||||
|
|
||||||
|
The jemalloc directory is pulled as a subtee from the upstream jemalloc github repo. To update it you should run from the project root:
|
||||||
|
|
||||||
|
1. `git subtree pull --prefix deps/jemalloc https://github.com/jemalloc/jemalloc.git <version-tag> --squash`<br>
|
||||||
|
This should hopefully merge the local changes into the new version.
|
||||||
|
2. In case any conflicts arise (due to our changes) you'll need to resolve them and commit.
|
||||||
|
3. Reconfigure jemalloc:<br>
|
||||||
|
```sh
|
||||||
|
rm deps/jemalloc/VERSION deps/jemalloc/configure
|
||||||
|
cd deps/jemalloc
|
||||||
|
./autogen.sh --with-version=<version-tag>-0-g0
|
||||||
|
```
|
||||||
|
4. Update jemalloc's version in `deps/Makefile`: search for "`--with-version=<old-version-tag>-0-g0`" and update it accordingly.
|
||||||
|
5. Commit the changes (VERSION,configure,Makefile).
|
||||||
|
|
||||||
Hiredis
|
Hiredis
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -78,5 +94,3 @@ and our version:
|
|||||||
1. Makefile is modified to allow a different compiler than GCC.
|
1. Makefile is modified to allow a different compiler than GCC.
|
||||||
2. We have the implementation source code, and directly link to the following external libraries: `lua_cjson.o`, `lua_struct.o`, `lua_cmsgpack.o` and `lua_bit.o`.
|
2. We have the implementation source code, and directly link to the following external libraries: `lua_cjson.o`, `lua_struct.o`, `lua_cmsgpack.o` and `lua_bit.o`.
|
||||||
3. There is a security fix in `ldo.c`, line 498: The check for `LUA_SIGNATURE[0]` is removed in order to avoid direct bytecode execution.
|
3. There is a security fix in `ldo.c`, line 498: The check for `LUA_SIGNATURE[0]` is removed in order to avoid direct bytecode execution.
|
||||||
|
|
||||||
|
|
||||||
|
16
deps/jemalloc/.appveyor.yml
vendored
16
deps/jemalloc/.appveyor.yml
vendored
@ -5,27 +5,27 @@ environment:
|
|||||||
- MSYSTEM: MINGW64
|
- MSYSTEM: MINGW64
|
||||||
CPU: x86_64
|
CPU: x86_64
|
||||||
MSVC: amd64
|
MSVC: amd64
|
||||||
|
CONFIG_FLAGS: --enable-debug
|
||||||
|
- MSYSTEM: MINGW64
|
||||||
|
CPU: x86_64
|
||||||
|
CONFIG_FLAGS: --enable-debug
|
||||||
- MSYSTEM: MINGW32
|
- MSYSTEM: MINGW32
|
||||||
CPU: i686
|
CPU: i686
|
||||||
MSVC: x86
|
MSVC: x86
|
||||||
- MSYSTEM: MINGW64
|
CONFIG_FLAGS: --enable-debug
|
||||||
CPU: x86_64
|
|
||||||
- MSYSTEM: MINGW32
|
- MSYSTEM: MINGW32
|
||||||
CPU: i686
|
CPU: i686
|
||||||
|
CONFIG_FLAGS: --enable-debug
|
||||||
- MSYSTEM: MINGW64
|
- MSYSTEM: MINGW64
|
||||||
CPU: x86_64
|
CPU: x86_64
|
||||||
MSVC: amd64
|
MSVC: amd64
|
||||||
CONFIG_FLAGS: --enable-debug
|
- MSYSTEM: MINGW64
|
||||||
|
CPU: x86_64
|
||||||
- MSYSTEM: MINGW32
|
- MSYSTEM: MINGW32
|
||||||
CPU: i686
|
CPU: i686
|
||||||
MSVC: x86
|
MSVC: x86
|
||||||
CONFIG_FLAGS: --enable-debug
|
|
||||||
- MSYSTEM: MINGW64
|
|
||||||
CPU: x86_64
|
|
||||||
CONFIG_FLAGS: --enable-debug
|
|
||||||
- MSYSTEM: MINGW32
|
- MSYSTEM: MINGW32
|
||||||
CPU: i686
|
CPU: i686
|
||||||
CONFIG_FLAGS: --enable-debug
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- set PATH=c:\msys64\%MSYSTEM%\bin;c:\msys64\usr\bin;%PATH%
|
- set PATH=c:\msys64\%MSYSTEM%\bin;c:\msys64\usr\bin;%PATH%
|
||||||
|
21
deps/jemalloc/.cirrus.yml
vendored
Normal file
21
deps/jemalloc/.cirrus.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
env:
|
||||||
|
CIRRUS_CLONE_DEPTH: 1
|
||||||
|
ARCH: amd64
|
||||||
|
|
||||||
|
task:
|
||||||
|
freebsd_instance:
|
||||||
|
matrix:
|
||||||
|
image: freebsd-12-0-release-amd64
|
||||||
|
image: freebsd-11-2-release-amd64
|
||||||
|
install_script:
|
||||||
|
- sed -i.bak -e 's,pkg+http://pkg.FreeBSD.org/\${ABI}/quarterly,pkg+http://pkg.FreeBSD.org/\${ABI}/latest,' /etc/pkg/FreeBSD.conf
|
||||||
|
- pkg upgrade -y
|
||||||
|
- pkg install -y autoconf gmake
|
||||||
|
script:
|
||||||
|
- autoconf
|
||||||
|
#- ./configure ${COMPILER_FLAGS:+ CC="$CC $COMPILER_FLAGS" CXX="$CXX $COMPILER_FLAGS" } $CONFIGURE_FLAGS
|
||||||
|
- ./configure
|
||||||
|
- export JFLAG=`sysctl -n kern.smp.cpus`
|
||||||
|
- gmake -j${JFLAG}
|
||||||
|
- gmake -j${JFLAG} tests
|
||||||
|
- gmake check
|
1
deps/jemalloc/.gitignore
vendored
1
deps/jemalloc/.gitignore
vendored
@ -30,7 +30,6 @@
|
|||||||
/include/jemalloc/internal/public_namespace.h
|
/include/jemalloc/internal/public_namespace.h
|
||||||
/include/jemalloc/internal/public_symbols.txt
|
/include/jemalloc/internal/public_symbols.txt
|
||||||
/include/jemalloc/internal/public_unnamespace.h
|
/include/jemalloc/internal/public_unnamespace.h
|
||||||
/include/jemalloc/internal/size_classes.h
|
|
||||||
/include/jemalloc/jemalloc.h
|
/include/jemalloc/jemalloc.h
|
||||||
/include/jemalloc/jemalloc_defs.h
|
/include/jemalloc/jemalloc_defs.h
|
||||||
/include/jemalloc/jemalloc_macros.h
|
/include/jemalloc/jemalloc_macros.h
|
||||||
|
105
deps/jemalloc/.travis.yml
vendored
105
deps/jemalloc/.travis.yml
vendored
@ -11,7 +11,7 @@ matrix:
|
|||||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
addons:
|
addons: &gcc_multilib
|
||||||
apt:
|
apt:
|
||||||
packages:
|
packages:
|
||||||
- gcc-multilib
|
- gcc-multilib
|
||||||
@ -21,6 +21,10 @@ matrix:
|
|||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
- os: linux
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
- os: linux
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: linux
|
- os: linux
|
||||||
@ -37,20 +41,25 @@ matrix:
|
|||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: osx
|
- os: osx
|
||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
- os: osx
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
- os: osx
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: osx
|
- os: osx
|
||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=clang CXX=clang++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
addons:
|
addons: *gcc_multilib
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- gcc-multilib
|
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
- os: linux
|
||||||
|
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
- os: linux
|
||||||
|
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: linux
|
- os: linux
|
||||||
@ -61,50 +70,39 @@ matrix:
|
|||||||
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
addons:
|
addons: *gcc_multilib
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- gcc-multilib
|
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
addons:
|
addons: *gcc_multilib
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- gcc-multilib
|
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
addons:
|
addons: *gcc_multilib
|
||||||
apt:
|
- os: linux
|
||||||
packages:
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- gcc-multilib
|
addons: *gcc_multilib
|
||||||
|
- os: linux
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
addons: *gcc_multilib
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
addons:
|
addons: *gcc_multilib
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- gcc-multilib
|
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
addons:
|
addons: *gcc_multilib
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- gcc-multilib
|
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
addons:
|
addons: *gcc_multilib
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- gcc-multilib
|
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
addons:
|
addons: *gcc_multilib
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- gcc-multilib
|
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
- os: linux
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
- os: linux
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: linux
|
- os: linux
|
||||||
@ -115,6 +113,10 @@ matrix:
|
|||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
- os: linux
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
- os: linux
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: linux
|
- os: linux
|
||||||
@ -123,6 +125,10 @@ matrix:
|
|||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
- os: linux
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
- os: linux
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: linux
|
- os: linux
|
||||||
@ -131,6 +137,24 @@ matrix:
|
|||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
- os: linux
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl --enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
- os: linux
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
- os: linux
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl --with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
- os: linux
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
- os: linux
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
- os: linux
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
- os: linux
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks --with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
- os: linux
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
- os: linux
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false,dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false,dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: linux
|
- os: linux
|
||||||
@ -143,10 +167,25 @@ matrix:
|
|||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary,background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary,background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=percpu_arena:percpu,background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=percpu_arena:percpu,background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
# Development build
|
||||||
|
- os: linux
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-cache-oblivious --enable-stats --enable-log --enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
# --enable-expermental-smallocx:
|
||||||
|
- os: linux
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --enable-experimental-smallocx --enable-stats --enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
|
||||||
|
# Valgrind
|
||||||
|
- os: linux
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" JEMALLOC_TEST_PREFIX="valgrind"
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- valgrind
|
||||||
|
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- autoconf
|
- autoconf
|
||||||
|
- scripts/gen_travis.py > travis_script && diff .travis.yml travis_script
|
||||||
- ./configure ${COMPILER_FLAGS:+ CC="$CC $COMPILER_FLAGS" CXX="$CXX $COMPILER_FLAGS" } $CONFIGURE_FLAGS
|
- ./configure ${COMPILER_FLAGS:+ CC="$CC $COMPILER_FLAGS" CXX="$CXX $COMPILER_FLAGS" } $CONFIGURE_FLAGS
|
||||||
- make -j3
|
- make -j3
|
||||||
- make -j3 tests
|
- make -j3 tests
|
||||||
|
4
deps/jemalloc/COPYING
vendored
4
deps/jemalloc/COPYING
vendored
@ -1,10 +1,10 @@
|
|||||||
Unless otherwise specified, files in the jemalloc source distribution are
|
Unless otherwise specified, files in the jemalloc source distribution are
|
||||||
subject to the following license:
|
subject to the following license:
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
Copyright (C) 2002-2018 Jason Evans <jasone@canonware.com>.
|
Copyright (C) 2002-present Jason Evans <jasone@canonware.com>.
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
Copyright (C) 2007-2012 Mozilla Foundation. All rights reserved.
|
Copyright (C) 2007-2012 Mozilla Foundation. All rights reserved.
|
||||||
Copyright (C) 2009-2018 Facebook, Inc. All rights reserved.
|
Copyright (C) 2009-present Facebook, Inc. All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
138
deps/jemalloc/ChangeLog
vendored
138
deps/jemalloc/ChangeLog
vendored
@ -4,7 +4,143 @@ brevity. Much more detail can be found in the git revision history:
|
|||||||
|
|
||||||
https://github.com/jemalloc/jemalloc
|
https://github.com/jemalloc/jemalloc
|
||||||
|
|
||||||
* 5.1.0 (May 4th, 2018)
|
* 5.2.1 (August 5, 2019)
|
||||||
|
|
||||||
|
This release is primarily about Windows. A critical virtual memory leak is
|
||||||
|
resolved on all Windows platforms. The regression was present in all releases
|
||||||
|
since 5.0.0.
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
- Fix a severe virtual memory leak on Windows. This regression was first
|
||||||
|
released in 5.0.0. (@Ignition, @j0t, @frederik-h, @davidtgoldblatt,
|
||||||
|
@interwq)
|
||||||
|
- Fix size 0 handling in posix_memalign(). This regression was first released
|
||||||
|
in 5.2.0. (@interwq)
|
||||||
|
- Fix the prof_log unit test which may observe unexpected backtraces from
|
||||||
|
compiler optimizations. The test was first added in 5.2.0. (@marxin,
|
||||||
|
@gnzlbg, @interwq)
|
||||||
|
- Fix the declaration of the extent_avail tree. This regression was first
|
||||||
|
released in 5.1.0. (@zoulasc)
|
||||||
|
- Fix an incorrect reference in jeprof. This functionality was first released
|
||||||
|
in 3.0.0. (@prehistoric-penguin)
|
||||||
|
- Fix an assertion on the deallocation fast-path. This regression was first
|
||||||
|
released in 5.2.0. (@yinan1048576)
|
||||||
|
- Fix the TLS_MODEL attribute in headers. This regression was first released
|
||||||
|
in 5.0.0. (@zoulasc, @interwq)
|
||||||
|
|
||||||
|
Optimizations and refactors:
|
||||||
|
- Implement opt.retain on Windows and enable by default on 64-bit. (@interwq,
|
||||||
|
@davidtgoldblatt)
|
||||||
|
- Optimize away a branch on the operator delete[] path. (@mgrice)
|
||||||
|
- Add format annotation to the format generator function. (@zoulasc)
|
||||||
|
- Refactor and improve the size class header generation. (@yinan1048576)
|
||||||
|
- Remove best fit. (@djwatson)
|
||||||
|
- Avoid blocking on background thread locks for stats. (@oranagra, @interwq)
|
||||||
|
|
||||||
|
* 5.2.0 (April 2, 2019)
|
||||||
|
|
||||||
|
This release includes a few notable improvements, which are summarized below:
|
||||||
|
1) improved fast-path performance from the optimizations by @djwatson; 2)
|
||||||
|
reduced virtual memory fragmentation and metadata usage; and 3) bug fixes on
|
||||||
|
setting the number of background threads. In addition, peak / spike memory
|
||||||
|
usage is improved with certain allocation patterns. As usual, the release and
|
||||||
|
prior dev versions have gone through large-scale production testing.
|
||||||
|
|
||||||
|
New features:
|
||||||
|
- Implement oversize_threshold, which uses a dedicated arena for allocations
|
||||||
|
crossing the specified threshold to reduce fragmentation. (@interwq)
|
||||||
|
- Add extents usage information to stats. (@tyleretzel)
|
||||||
|
- Log time information for sampled allocations. (@tyleretzel)
|
||||||
|
- Support 0 size in sdallocx. (@djwatson)
|
||||||
|
- Output rate for certain counters in malloc_stats. (@zinoale)
|
||||||
|
- Add configure option --enable-readlinkat, which allows the use of readlinkat
|
||||||
|
over readlink. (@davidtgoldblatt)
|
||||||
|
- Add configure options --{enable,disable}-{static,shared} to allow not
|
||||||
|
building unwanted libraries. (@Ericson2314)
|
||||||
|
- Add configure option --disable-libdl to enable fully static builds.
|
||||||
|
(@interwq)
|
||||||
|
- Add mallctl interfaces:
|
||||||
|
+ opt.oversize_threshold (@interwq)
|
||||||
|
+ stats.arenas.<i>.extent_avail (@tyleretzel)
|
||||||
|
+ stats.arenas.<i>.extents.<j>.n{dirty,muzzy,retained} (@tyleretzel)
|
||||||
|
+ stats.arenas.<i>.extents.<j>.{dirty,muzzy,retained}_bytes
|
||||||
|
(@tyleretzel)
|
||||||
|
|
||||||
|
Portability improvements:
|
||||||
|
- Update MSVC builds. (@maksqwe, @rustyx)
|
||||||
|
- Workaround a compiler optimizer bug on s390x. (@rkmisra)
|
||||||
|
- Make use of pthread_set_name_np(3) on FreeBSD. (@trasz)
|
||||||
|
- Implement malloc_getcpu() to enable percpu_arena for windows. (@santagada)
|
||||||
|
- Link against -pthread instead of -lpthread. (@paravoid)
|
||||||
|
- Make background_thread not dependent on libdl. (@interwq)
|
||||||
|
- Add stringify to fix a linker directive issue on MSVC. (@daverigby)
|
||||||
|
- Detect and fall back when 8-bit atomics are unavailable. (@interwq)
|
||||||
|
- Fall back to the default pthread_create if dlsym(3) fails. (@interwq)
|
||||||
|
|
||||||
|
Optimizations and refactors:
|
||||||
|
- Refactor the TSD module. (@davidtgoldblatt)
|
||||||
|
- Avoid taking extents_muzzy mutex when muzzy is disabled. (@interwq)
|
||||||
|
- Avoid taking large_mtx for auto arenas on the tcache flush path. (@interwq)
|
||||||
|
- Optimize ixalloc by avoiding a size lookup. (@interwq)
|
||||||
|
- Implement opt.oversize_threshold which uses a dedicated arena for requests
|
||||||
|
crossing the threshold, also eagerly purges the oversize extents. Default
|
||||||
|
the threshold to 8 MiB. (@interwq)
|
||||||
|
- Clean compilation with -Wextra. (@gnzlbg, @jasone)
|
||||||
|
- Refactor the size class module. (@davidtgoldblatt)
|
||||||
|
- Refactor the stats emitter. (@tyleretzel)
|
||||||
|
- Optimize pow2_ceil. (@rkmisra)
|
||||||
|
- Avoid runtime detection of lazy purging on FreeBSD. (@trasz)
|
||||||
|
- Optimize mmap(2) alignment handling on FreeBSD. (@trasz)
|
||||||
|
- Improve error handling for THP state initialization. (@jsteemann)
|
||||||
|
- Rework the malloc() fast path. (@djwatson)
|
||||||
|
- Rework the free() fast path. (@djwatson)
|
||||||
|
- Refactor and optimize the tcache fill / flush paths. (@djwatson)
|
||||||
|
- Optimize sync / lwsync on PowerPC. (@chmeeedalf)
|
||||||
|
- Bypass extent_dalloc() when retain is enabled. (@interwq)
|
||||||
|
- Optimize the locking on large deallocation. (@interwq)
|
||||||
|
- Reduce the number of pages committed from sanity checking in debug build.
|
||||||
|
(@trasz, @interwq)
|
||||||
|
- Deprecate OSSpinLock. (@interwq)
|
||||||
|
- Lower the default number of background threads to 4 (when the feature
|
||||||
|
is enabled). (@interwq)
|
||||||
|
- Optimize the trylock spin wait. (@djwatson)
|
||||||
|
- Use arena index for arena-matching checks. (@interwq)
|
||||||
|
- Avoid forced decay on thread termination when using background threads.
|
||||||
|
(@interwq)
|
||||||
|
- Disable muzzy decay by default. (@djwatson, @interwq)
|
||||||
|
- Only initialize libgcc unwinder when profiling is enabled. (@paravoid,
|
||||||
|
@interwq)
|
||||||
|
|
||||||
|
Bug fixes (all only relevant to jemalloc 5.x):
|
||||||
|
- Fix background thread index issues with max_background_threads. (@djwatson,
|
||||||
|
@interwq)
|
||||||
|
- Fix stats output for opt.lg_extent_max_active_fit. (@interwq)
|
||||||
|
- Fix opt.prof_prefix initialization. (@davidtgoldblatt)
|
||||||
|
- Properly trigger decay on tcache destroy. (@interwq, @amosbird)
|
||||||
|
- Fix tcache.flush. (@interwq)
|
||||||
|
- Detect whether explicit extent zero out is necessary with huge pages or
|
||||||
|
custom extent hooks, which may change the purge semantics. (@interwq)
|
||||||
|
- Fix a side effect caused by extent_max_active_fit combined with decay-based
|
||||||
|
purging, where freed extents can accumulate and not be reused for an
|
||||||
|
extended period of time. (@interwq, @mpghf)
|
||||||
|
- Fix a missing unlock on extent register error handling. (@zoulasc)
|
||||||
|
|
||||||
|
Testing:
|
||||||
|
- Simplify the Travis script output. (@gnzlbg)
|
||||||
|
- Update the test scripts for FreeBSD. (@devnexen)
|
||||||
|
- Add unit tests for the producer-consumer pattern. (@interwq)
|
||||||
|
- Add Cirrus-CI config for FreeBSD builds. (@jasone)
|
||||||
|
- Add size-matching sanity checks on tcache flush. (@davidtgoldblatt,
|
||||||
|
@interwq)
|
||||||
|
|
||||||
|
Incompatible changes:
|
||||||
|
- Remove --with-lg-page-sizes. (@davidtgoldblatt)
|
||||||
|
|
||||||
|
Documentation:
|
||||||
|
- Attempt to build docs by default, however skip doc building when xsltproc
|
||||||
|
is missing. (@interwq, @cmuellner)
|
||||||
|
|
||||||
|
* 5.1.0 (May 4, 2018)
|
||||||
|
|
||||||
This release is primarily about fine-tuning, ranging from several new features
|
This release is primarily about fine-tuning, ranging from several new features
|
||||||
to numerous notable performance and portability enhancements. The release and
|
to numerous notable performance and portability enhancements. The release and
|
||||||
|
12
deps/jemalloc/INSTALL.md
vendored
12
deps/jemalloc/INSTALL.md
vendored
@ -221,13 +221,6 @@ any of the following arguments (not a definitive list) to 'configure':
|
|||||||
system page size may change between configuration and execution, e.g. when
|
system page size may change between configuration and execution, e.g. when
|
||||||
cross compiling.
|
cross compiling.
|
||||||
|
|
||||||
* `--with-lg-page-sizes=<lg-page-sizes>`
|
|
||||||
|
|
||||||
Specify the comma-separated base 2 logs of the page sizes to support. This
|
|
||||||
option may be useful when cross compiling in combination with
|
|
||||||
`--with-lg-page`, but its primary use case is for integration with FreeBSD's
|
|
||||||
libc, wherein jemalloc is embedded.
|
|
||||||
|
|
||||||
* `--with-lg-hugepage=<lg-hugepage>`
|
* `--with-lg-hugepage=<lg-hugepage>`
|
||||||
|
|
||||||
Specify the base 2 log of the system huge page size. This option is useful
|
Specify the base 2 log of the system huge page size. This option is useful
|
||||||
@ -276,6 +269,11 @@ any of the following arguments (not a definitive list) to 'configure':
|
|||||||
in the same process, which will almost certainly result in confusing runtime
|
in the same process, which will almost certainly result in confusing runtime
|
||||||
crashes if pointers leak from one implementation to the other.
|
crashes if pointers leak from one implementation to the other.
|
||||||
|
|
||||||
|
* `--disable-libdl`
|
||||||
|
|
||||||
|
Disable the usage of libdl, namely dlsym(3) which is required by the lazy
|
||||||
|
lock option. This can allow building static binaries.
|
||||||
|
|
||||||
The following environment variables (not a definitive list) impact configure's
|
The following environment variables (not a definitive list) impact configure's
|
||||||
behavior:
|
behavior:
|
||||||
|
|
||||||
|
70
deps/jemalloc/Makefile.in
vendored
70
deps/jemalloc/Makefile.in
vendored
@ -47,6 +47,7 @@ REV := @rev@
|
|||||||
install_suffix := @install_suffix@
|
install_suffix := @install_suffix@
|
||||||
ABI := @abi@
|
ABI := @abi@
|
||||||
XSLTPROC := @XSLTPROC@
|
XSLTPROC := @XSLTPROC@
|
||||||
|
XSLROOT := @XSLROOT@
|
||||||
AUTOCONF := @AUTOCONF@
|
AUTOCONF := @AUTOCONF@
|
||||||
_RPATH = @RPATH@
|
_RPATH = @RPATH@
|
||||||
RPATH = $(if $(1),$(call _RPATH,$(1)))
|
RPATH = $(if $(1),$(call _RPATH,$(1)))
|
||||||
@ -55,8 +56,12 @@ cfghdrs_out := @cfghdrs_out@
|
|||||||
cfgoutputs_in := $(addprefix $(srcroot),@cfgoutputs_in@)
|
cfgoutputs_in := $(addprefix $(srcroot),@cfgoutputs_in@)
|
||||||
cfgoutputs_out := @cfgoutputs_out@
|
cfgoutputs_out := @cfgoutputs_out@
|
||||||
enable_autogen := @enable_autogen@
|
enable_autogen := @enable_autogen@
|
||||||
|
enable_doc := @enable_doc@
|
||||||
|
enable_shared := @enable_shared@
|
||||||
|
enable_static := @enable_static@
|
||||||
enable_prof := @enable_prof@
|
enable_prof := @enable_prof@
|
||||||
enable_zone_allocator := @enable_zone_allocator@
|
enable_zone_allocator := @enable_zone_allocator@
|
||||||
|
enable_experimental_smallocx := @enable_experimental_smallocx@
|
||||||
MALLOC_CONF := @JEMALLOC_CPREFIX@MALLOC_CONF
|
MALLOC_CONF := @JEMALLOC_CPREFIX@MALLOC_CONF
|
||||||
link_whole_archive := @link_whole_archive@
|
link_whole_archive := @link_whole_archive@
|
||||||
DSO_LDFLAGS = @DSO_LDFLAGS@
|
DSO_LDFLAGS = @DSO_LDFLAGS@
|
||||||
@ -102,7 +107,7 @@ C_SRCS := $(srcroot)src/jemalloc.c \
|
|||||||
$(srcroot)src/extent_dss.c \
|
$(srcroot)src/extent_dss.c \
|
||||||
$(srcroot)src/extent_mmap.c \
|
$(srcroot)src/extent_mmap.c \
|
||||||
$(srcroot)src/hash.c \
|
$(srcroot)src/hash.c \
|
||||||
$(srcroot)src/hooks.c \
|
$(srcroot)src/hook.c \
|
||||||
$(srcroot)src/large.c \
|
$(srcroot)src/large.c \
|
||||||
$(srcroot)src/log.c \
|
$(srcroot)src/log.c \
|
||||||
$(srcroot)src/malloc_io.c \
|
$(srcroot)src/malloc_io.c \
|
||||||
@ -113,9 +118,12 @@ C_SRCS := $(srcroot)src/jemalloc.c \
|
|||||||
$(srcroot)src/prng.c \
|
$(srcroot)src/prng.c \
|
||||||
$(srcroot)src/prof.c \
|
$(srcroot)src/prof.c \
|
||||||
$(srcroot)src/rtree.c \
|
$(srcroot)src/rtree.c \
|
||||||
|
$(srcroot)src/safety_check.c \
|
||||||
$(srcroot)src/stats.c \
|
$(srcroot)src/stats.c \
|
||||||
|
$(srcroot)src/sc.c \
|
||||||
$(srcroot)src/sz.c \
|
$(srcroot)src/sz.c \
|
||||||
$(srcroot)src/tcache.c \
|
$(srcroot)src/tcache.c \
|
||||||
|
$(srcroot)src/test_hooks.c \
|
||||||
$(srcroot)src/ticker.c \
|
$(srcroot)src/ticker.c \
|
||||||
$(srcroot)src/tsd.c \
|
$(srcroot)src/tsd.c \
|
||||||
$(srcroot)src/witness.c
|
$(srcroot)src/witness.c
|
||||||
@ -165,14 +173,18 @@ TESTS_UNIT := \
|
|||||||
$(srcroot)test/unit/background_thread_enable.c \
|
$(srcroot)test/unit/background_thread_enable.c \
|
||||||
$(srcroot)test/unit/base.c \
|
$(srcroot)test/unit/base.c \
|
||||||
$(srcroot)test/unit/bitmap.c \
|
$(srcroot)test/unit/bitmap.c \
|
||||||
|
$(srcroot)test/unit/bit_util.c \
|
||||||
|
$(srcroot)test/unit/binshard.c \
|
||||||
$(srcroot)test/unit/ckh.c \
|
$(srcroot)test/unit/ckh.c \
|
||||||
$(srcroot)test/unit/decay.c \
|
$(srcroot)test/unit/decay.c \
|
||||||
$(srcroot)test/unit/div.c \
|
$(srcroot)test/unit/div.c \
|
||||||
$(srcroot)test/unit/emitter.c \
|
$(srcroot)test/unit/emitter.c \
|
||||||
$(srcroot)test/unit/extent_quantize.c \
|
$(srcroot)test/unit/extent_quantize.c \
|
||||||
|
$(srcroot)test/unit/extent_util.c \
|
||||||
$(srcroot)test/unit/fork.c \
|
$(srcroot)test/unit/fork.c \
|
||||||
$(srcroot)test/unit/hash.c \
|
$(srcroot)test/unit/hash.c \
|
||||||
$(srcroot)test/unit/hooks.c \
|
$(srcroot)test/unit/hook.c \
|
||||||
|
$(srcroot)test/unit/huge.c \
|
||||||
$(srcroot)test/unit/junk.c \
|
$(srcroot)test/unit/junk.c \
|
||||||
$(srcroot)test/unit/junk_alloc.c \
|
$(srcroot)test/unit/junk_alloc.c \
|
||||||
$(srcroot)test/unit/junk_free.c \
|
$(srcroot)test/unit/junk_free.c \
|
||||||
@ -190,6 +202,7 @@ TESTS_UNIT := \
|
|||||||
$(srcroot)test/unit/prof_active.c \
|
$(srcroot)test/unit/prof_active.c \
|
||||||
$(srcroot)test/unit/prof_gdump.c \
|
$(srcroot)test/unit/prof_gdump.c \
|
||||||
$(srcroot)test/unit/prof_idump.c \
|
$(srcroot)test/unit/prof_idump.c \
|
||||||
|
$(srcroot)test/unit/prof_log.c \
|
||||||
$(srcroot)test/unit/prof_reset.c \
|
$(srcroot)test/unit/prof_reset.c \
|
||||||
$(srcroot)test/unit/prof_tctx.c \
|
$(srcroot)test/unit/prof_tctx.c \
|
||||||
$(srcroot)test/unit/prof_thread_name.c \
|
$(srcroot)test/unit/prof_thread_name.c \
|
||||||
@ -198,13 +211,17 @@ TESTS_UNIT := \
|
|||||||
$(srcroot)test/unit/rb.c \
|
$(srcroot)test/unit/rb.c \
|
||||||
$(srcroot)test/unit/retained.c \
|
$(srcroot)test/unit/retained.c \
|
||||||
$(srcroot)test/unit/rtree.c \
|
$(srcroot)test/unit/rtree.c \
|
||||||
|
$(srcroot)test/unit/safety_check.c \
|
||||||
|
$(srcroot)test/unit/seq.c \
|
||||||
$(srcroot)test/unit/SFMT.c \
|
$(srcroot)test/unit/SFMT.c \
|
||||||
|
$(srcroot)test/unit/sc.c \
|
||||||
$(srcroot)test/unit/size_classes.c \
|
$(srcroot)test/unit/size_classes.c \
|
||||||
$(srcroot)test/unit/slab.c \
|
$(srcroot)test/unit/slab.c \
|
||||||
$(srcroot)test/unit/smoothstep.c \
|
$(srcroot)test/unit/smoothstep.c \
|
||||||
$(srcroot)test/unit/spin.c \
|
$(srcroot)test/unit/spin.c \
|
||||||
$(srcroot)test/unit/stats.c \
|
$(srcroot)test/unit/stats.c \
|
||||||
$(srcroot)test/unit/stats_print.c \
|
$(srcroot)test/unit/stats_print.c \
|
||||||
|
$(srcroot)test/unit/test_hooks.c \
|
||||||
$(srcroot)test/unit/ticker.c \
|
$(srcroot)test/unit/ticker.c \
|
||||||
$(srcroot)test/unit/nstime.c \
|
$(srcroot)test/unit/nstime.c \
|
||||||
$(srcroot)test/unit/tsd.c \
|
$(srcroot)test/unit/tsd.c \
|
||||||
@ -217,15 +234,21 @@ endif
|
|||||||
TESTS_INTEGRATION := $(srcroot)test/integration/aligned_alloc.c \
|
TESTS_INTEGRATION := $(srcroot)test/integration/aligned_alloc.c \
|
||||||
$(srcroot)test/integration/allocated.c \
|
$(srcroot)test/integration/allocated.c \
|
||||||
$(srcroot)test/integration/extent.c \
|
$(srcroot)test/integration/extent.c \
|
||||||
|
$(srcroot)test/integration/malloc.c \
|
||||||
$(srcroot)test/integration/mallocx.c \
|
$(srcroot)test/integration/mallocx.c \
|
||||||
$(srcroot)test/integration/MALLOCX_ARENA.c \
|
$(srcroot)test/integration/MALLOCX_ARENA.c \
|
||||||
$(srcroot)test/integration/overflow.c \
|
$(srcroot)test/integration/overflow.c \
|
||||||
$(srcroot)test/integration/posix_memalign.c \
|
$(srcroot)test/integration/posix_memalign.c \
|
||||||
$(srcroot)test/integration/rallocx.c \
|
$(srcroot)test/integration/rallocx.c \
|
||||||
$(srcroot)test/integration/sdallocx.c \
|
$(srcroot)test/integration/sdallocx.c \
|
||||||
|
$(srcroot)test/integration/slab_sizes.c \
|
||||||
$(srcroot)test/integration/thread_arena.c \
|
$(srcroot)test/integration/thread_arena.c \
|
||||||
$(srcroot)test/integration/thread_tcache_enabled.c \
|
$(srcroot)test/integration/thread_tcache_enabled.c \
|
||||||
$(srcroot)test/integration/xallocx.c
|
$(srcroot)test/integration/xallocx.c
|
||||||
|
ifeq (@enable_experimental_smallocx@, 1)
|
||||||
|
TESTS_INTEGRATION += \
|
||||||
|
$(srcroot)test/integration/smallocx.c
|
||||||
|
endif
|
||||||
ifeq (@enable_cxx@, 1)
|
ifeq (@enable_cxx@, 1)
|
||||||
CPP_SRCS := $(srcroot)src/jemalloc_cpp.cpp
|
CPP_SRCS := $(srcroot)src/jemalloc_cpp.cpp
|
||||||
TESTS_INTEGRATION_CPP := $(srcroot)test/integration/cpp/basic.cpp
|
TESTS_INTEGRATION_CPP := $(srcroot)test/integration/cpp/basic.cpp
|
||||||
@ -233,7 +256,9 @@ else
|
|||||||
CPP_SRCS :=
|
CPP_SRCS :=
|
||||||
TESTS_INTEGRATION_CPP :=
|
TESTS_INTEGRATION_CPP :=
|
||||||
endif
|
endif
|
||||||
TESTS_STRESS := $(srcroot)test/stress/microbench.c
|
TESTS_STRESS := $(srcroot)test/stress/microbench.c \
|
||||||
|
$(srcroot)test/stress/hookbench.c
|
||||||
|
|
||||||
|
|
||||||
TESTS := $(TESTS_UNIT) $(TESTS_INTEGRATION) $(TESTS_INTEGRATION_CPP) $(TESTS_STRESS)
|
TESTS := $(TESTS_UNIT) $(TESTS_INTEGRATION) $(TESTS_INTEGRATION_CPP) $(TESTS_STRESS)
|
||||||
|
|
||||||
@ -274,10 +299,24 @@ all: build_lib
|
|||||||
dist: build_doc
|
dist: build_doc
|
||||||
|
|
||||||
$(objroot)doc/%.html : $(objroot)doc/%.xml $(srcroot)doc/stylesheet.xsl $(objroot)doc/html.xsl
|
$(objroot)doc/%.html : $(objroot)doc/%.xml $(srcroot)doc/stylesheet.xsl $(objroot)doc/html.xsl
|
||||||
|
ifneq ($(XSLROOT),)
|
||||||
$(XSLTPROC) -o $@ $(objroot)doc/html.xsl $<
|
$(XSLTPROC) -o $@ $(objroot)doc/html.xsl $<
|
||||||
|
else
|
||||||
|
ifeq ($(wildcard $(DOCS_HTML)),)
|
||||||
|
@echo "<p>Missing xsltproc. Doc not built.</p>" > $@
|
||||||
|
endif
|
||||||
|
@echo "Missing xsltproc. "$@" not (re)built."
|
||||||
|
endif
|
||||||
|
|
||||||
$(objroot)doc/%.3 : $(objroot)doc/%.xml $(srcroot)doc/stylesheet.xsl $(objroot)doc/manpages.xsl
|
$(objroot)doc/%.3 : $(objroot)doc/%.xml $(srcroot)doc/stylesheet.xsl $(objroot)doc/manpages.xsl
|
||||||
|
ifneq ($(XSLROOT),)
|
||||||
$(XSLTPROC) -o $@ $(objroot)doc/manpages.xsl $<
|
$(XSLTPROC) -o $@ $(objroot)doc/manpages.xsl $<
|
||||||
|
else
|
||||||
|
ifeq ($(wildcard $(DOCS_MAN3)),)
|
||||||
|
@echo "Missing xsltproc. Doc not built." > $@
|
||||||
|
endif
|
||||||
|
@echo "Missing xsltproc. "$@" not (re)built."
|
||||||
|
endif
|
||||||
|
|
||||||
build_doc_html: $(DOCS_HTML)
|
build_doc_html: $(DOCS_HTML)
|
||||||
build_doc_man: $(DOCS_MAN3)
|
build_doc_man: $(DOCS_MAN3)
|
||||||
@ -400,7 +439,7 @@ $(objroot)test/unit/%$(EXE): $(objroot)test/unit/%.$(O) $(C_JET_OBJS) $(C_TESTLI
|
|||||||
|
|
||||||
$(objroot)test/integration/%$(EXE): $(objroot)test/integration/%.$(O) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB)
|
$(objroot)test/integration/%$(EXE): $(objroot)test/integration/%.$(O) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB)
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
$(CC) $(TEST_LD_MODE) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(LJEMALLOC) $(LDFLAGS) $(filter-out -lm,$(filter -lrt -lpthread -lstdc++,$(LIBS))) $(LM) $(EXTRA_LDFLAGS)
|
$(CC) $(TEST_LD_MODE) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(LJEMALLOC) $(LDFLAGS) $(filter-out -lm,$(filter -lrt -pthread -lstdc++,$(LIBS))) $(LM) $(EXTRA_LDFLAGS)
|
||||||
|
|
||||||
$(objroot)test/integration/cpp/%$(EXE): $(objroot)test/integration/cpp/%.$(O) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB)
|
$(objroot)test/integration/cpp/%$(EXE): $(objroot)test/integration/cpp/%.$(O) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB)
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@ -412,7 +451,12 @@ $(objroot)test/stress/%$(EXE): $(objroot)test/stress/%.$(O) $(C_JET_OBJS) $(C_TE
|
|||||||
|
|
||||||
build_lib_shared: $(DSOS)
|
build_lib_shared: $(DSOS)
|
||||||
build_lib_static: $(STATIC_LIBS)
|
build_lib_static: $(STATIC_LIBS)
|
||||||
build_lib: build_lib_shared build_lib_static
|
ifeq ($(enable_shared), 1)
|
||||||
|
build_lib: build_lib_shared
|
||||||
|
endif
|
||||||
|
ifeq ($(enable_static), 1)
|
||||||
|
build_lib: build_lib_static
|
||||||
|
endif
|
||||||
|
|
||||||
install_bin:
|
install_bin:
|
||||||
$(INSTALL) -d $(BINDIR)
|
$(INSTALL) -d $(BINDIR)
|
||||||
@ -449,7 +493,13 @@ install_lib_pc: $(PC)
|
|||||||
$(INSTALL) -m 644 $$l $(LIBDIR)/pkgconfig; \
|
$(INSTALL) -m 644 $$l $(LIBDIR)/pkgconfig; \
|
||||||
done
|
done
|
||||||
|
|
||||||
install_lib: install_lib_shared install_lib_static install_lib_pc
|
ifeq ($(enable_shared), 1)
|
||||||
|
install_lib: install_lib_shared
|
||||||
|
endif
|
||||||
|
ifeq ($(enable_static), 1)
|
||||||
|
install_lib: install_lib_static
|
||||||
|
endif
|
||||||
|
install_lib: install_lib_pc
|
||||||
|
|
||||||
install_doc_html:
|
install_doc_html:
|
||||||
$(INSTALL) -d $(DATADIR)/doc/jemalloc$(install_suffix)
|
$(INSTALL) -d $(DATADIR)/doc/jemalloc$(install_suffix)
|
||||||
@ -465,9 +515,13 @@ install_doc_man:
|
|||||||
$(INSTALL) -m 644 $$d $(MANDIR)/man3; \
|
$(INSTALL) -m 644 $$d $(MANDIR)/man3; \
|
||||||
done
|
done
|
||||||
|
|
||||||
install_doc: install_doc_html install_doc_man
|
install_doc: build_doc install_doc_html install_doc_man
|
||||||
|
|
||||||
install: install_bin install_include install_lib install_doc
|
install: install_bin install_include install_lib
|
||||||
|
|
||||||
|
ifeq ($(enable_doc), 1)
|
||||||
|
install: install_doc
|
||||||
|
endif
|
||||||
|
|
||||||
tests_unit: $(TESTS_UNIT:$(srcroot)%.c=$(objroot)%$(EXE))
|
tests_unit: $(TESTS_UNIT:$(srcroot)%.c=$(objroot)%$(EXE))
|
||||||
tests_integration: $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%$(EXE)) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%$(EXE))
|
tests_integration: $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%$(EXE)) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%$(EXE))
|
||||||
|
2
deps/jemalloc/VERSION
vendored
2
deps/jemalloc/VERSION
vendored
@ -1 +1 @@
|
|||||||
5.1.0-0-g0
|
5.2.1-0-g0
|
||||||
|
3
deps/jemalloc/bin/jeprof.in
vendored
3
deps/jemalloc/bin/jeprof.in
vendored
@ -2909,6 +2909,7 @@ sub RemoveUninterestingFrames {
|
|||||||
'@JEMALLOC_PREFIX@xallocx',
|
'@JEMALLOC_PREFIX@xallocx',
|
||||||
'@JEMALLOC_PREFIX@dallocx',
|
'@JEMALLOC_PREFIX@dallocx',
|
||||||
'@JEMALLOC_PREFIX@sdallocx',
|
'@JEMALLOC_PREFIX@sdallocx',
|
||||||
|
'@JEMALLOC_PREFIX@sdallocx_noflags',
|
||||||
'tc_calloc',
|
'tc_calloc',
|
||||||
'tc_cfree',
|
'tc_cfree',
|
||||||
'tc_malloc',
|
'tc_malloc',
|
||||||
@ -5366,7 +5367,7 @@ sub GetProcedureBoundaries {
|
|||||||
my $demangle_flag = "";
|
my $demangle_flag = "";
|
||||||
my $cppfilt_flag = "";
|
my $cppfilt_flag = "";
|
||||||
my $to_devnull = ">$dev_null 2>&1";
|
my $to_devnull = ">$dev_null 2>&1";
|
||||||
if (system(ShellEscape($nm, "--demangle", "image") . $to_devnull) == 0) {
|
if (system(ShellEscape($nm, "--demangle", $image) . $to_devnull) == 0) {
|
||||||
# In this mode, we do "nm --demangle <foo>"
|
# In this mode, we do "nm --demangle <foo>"
|
||||||
$demangle_flag = "--demangle";
|
$demangle_flag = "--demangle";
|
||||||
$cppfilt_flag = "";
|
$cppfilt_flag = "";
|
||||||
|
848
deps/jemalloc/configure
vendored
848
deps/jemalloc/configure
vendored
File diff suppressed because it is too large
Load Diff
368
deps/jemalloc/configure.ac
vendored
368
deps/jemalloc/configure.ac
vendored
@ -175,6 +175,9 @@ fi
|
|||||||
],
|
],
|
||||||
XSLROOT="${DEFAULT_XSLROOT}"
|
XSLROOT="${DEFAULT_XSLROOT}"
|
||||||
)
|
)
|
||||||
|
if test "x$XSLTPROC" = "xfalse" ; then
|
||||||
|
XSLROOT=""
|
||||||
|
fi
|
||||||
AC_SUBST([XSLROOT])
|
AC_SUBST([XSLROOT])
|
||||||
|
|
||||||
dnl If CFLAGS isn't defined, set CFLAGS to something reasonable. Otherwise,
|
dnl If CFLAGS isn't defined, set CFLAGS to something reasonable. Otherwise,
|
||||||
@ -242,6 +245,7 @@ if test "x$GCC" = "xyes" ; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
JE_CFLAGS_ADD([-Wall])
|
JE_CFLAGS_ADD([-Wall])
|
||||||
|
JE_CFLAGS_ADD([-Wextra])
|
||||||
JE_CFLAGS_ADD([-Wshorten-64-to-32])
|
JE_CFLAGS_ADD([-Wshorten-64-to-32])
|
||||||
JE_CFLAGS_ADD([-Wsign-compare])
|
JE_CFLAGS_ADD([-Wsign-compare])
|
||||||
JE_CFLAGS_ADD([-Wundef])
|
JE_CFLAGS_ADD([-Wundef])
|
||||||
@ -289,6 +293,7 @@ if test "x$enable_cxx" = "x1" ; then
|
|||||||
AX_CXX_COMPILE_STDCXX([14], [noext], [optional])
|
AX_CXX_COMPILE_STDCXX([14], [noext], [optional])
|
||||||
if test "x${HAVE_CXX14}" = "x1" ; then
|
if test "x${HAVE_CXX14}" = "x1" ; then
|
||||||
JE_CXXFLAGS_ADD([-Wall])
|
JE_CXXFLAGS_ADD([-Wall])
|
||||||
|
JE_CXXFLAGS_ADD([-Wextra])
|
||||||
JE_CXXFLAGS_ADD([-g3])
|
JE_CXXFLAGS_ADD([-g3])
|
||||||
|
|
||||||
SAVED_LIBS="${LIBS}"
|
SAVED_LIBS="${LIBS}"
|
||||||
@ -536,6 +541,66 @@ AC_PROG_NM
|
|||||||
|
|
||||||
AC_PROG_AWK
|
AC_PROG_AWK
|
||||||
|
|
||||||
|
dnl ============================================================================
|
||||||
|
dnl jemalloc version.
|
||||||
|
dnl
|
||||||
|
|
||||||
|
AC_ARG_WITH([version],
|
||||||
|
[AS_HELP_STRING([--with-version=<major>.<minor>.<bugfix>-<nrev>-g<gid>],
|
||||||
|
[Version string])],
|
||||||
|
[
|
||||||
|
echo "${with_version}" | grep ['^[0-9]\+\.[0-9]\+\.[0-9]\+-[0-9]\+-g[0-9a-f]\+$'] 2>&1 1>/dev/null
|
||||||
|
if test $? -eq 0 ; then
|
||||||
|
echo "$with_version" > "${objroot}VERSION"
|
||||||
|
else
|
||||||
|
echo "${with_version}" | grep ['^VERSION$'] 2>&1 1>/dev/null
|
||||||
|
if test $? -ne 0 ; then
|
||||||
|
AC_MSG_ERROR([${with_version} does not match <major>.<minor>.<bugfix>-<nrev>-g<gid> or VERSION])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
], [
|
||||||
|
dnl Set VERSION if source directory is inside a git repository.
|
||||||
|
if test "x`test ! \"${srcroot}\" && cd \"${srcroot}\"; git rev-parse --is-inside-work-tree 2>/dev/null`" = "xtrue" ; then
|
||||||
|
dnl Pattern globs aren't powerful enough to match both single- and
|
||||||
|
dnl double-digit version numbers, so iterate over patterns to support up
|
||||||
|
dnl to version 99.99.99 without any accidental matches.
|
||||||
|
for pattern in ['[0-9].[0-9].[0-9]' '[0-9].[0-9].[0-9][0-9]' \
|
||||||
|
'[0-9].[0-9][0-9].[0-9]' '[0-9].[0-9][0-9].[0-9][0-9]' \
|
||||||
|
'[0-9][0-9].[0-9].[0-9]' '[0-9][0-9].[0-9].[0-9][0-9]' \
|
||||||
|
'[0-9][0-9].[0-9][0-9].[0-9]' \
|
||||||
|
'[0-9][0-9].[0-9][0-9].[0-9][0-9]']; do
|
||||||
|
(test ! "${srcroot}" && cd "${srcroot}"; git describe --long --abbrev=40 --match="${pattern}") > "${objroot}VERSION.tmp" 2>/dev/null
|
||||||
|
if test $? -eq 0 ; then
|
||||||
|
mv "${objroot}VERSION.tmp" "${objroot}VERSION"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
rm -f "${objroot}VERSION.tmp"
|
||||||
|
])
|
||||||
|
|
||||||
|
if test ! -e "${objroot}VERSION" ; then
|
||||||
|
if test ! -e "${srcroot}VERSION" ; then
|
||||||
|
AC_MSG_RESULT(
|
||||||
|
[Missing VERSION file, and unable to generate it; creating bogus VERSION])
|
||||||
|
echo "0.0.0-0-g0000000000000000000000000000000000000000" > "${objroot}VERSION"
|
||||||
|
else
|
||||||
|
cp ${srcroot}VERSION ${objroot}VERSION
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
jemalloc_version=`cat "${objroot}VERSION"`
|
||||||
|
jemalloc_version_major=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]1}'`
|
||||||
|
jemalloc_version_minor=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]2}'`
|
||||||
|
jemalloc_version_bugfix=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]3}'`
|
||||||
|
jemalloc_version_nrev=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]4}'`
|
||||||
|
jemalloc_version_gid=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]5}'`
|
||||||
|
AC_SUBST([jemalloc_version])
|
||||||
|
AC_SUBST([jemalloc_version_major])
|
||||||
|
AC_SUBST([jemalloc_version_minor])
|
||||||
|
AC_SUBST([jemalloc_version_bugfix])
|
||||||
|
AC_SUBST([jemalloc_version_nrev])
|
||||||
|
AC_SUBST([jemalloc_version_gid])
|
||||||
|
|
||||||
dnl Platform-specific settings. abi and RPATH can probably be determined
|
dnl Platform-specific settings. abi and RPATH can probably be determined
|
||||||
dnl programmatically, but doing so is error-prone, which makes it generally
|
dnl programmatically, but doing so is error-prone, which makes it generally
|
||||||
dnl not worth the trouble.
|
dnl not worth the trouble.
|
||||||
@ -673,6 +738,9 @@ case "${host}" in
|
|||||||
libprefix=""
|
libprefix=""
|
||||||
SOREV="${so}"
|
SOREV="${so}"
|
||||||
PIC_CFLAGS=""
|
PIC_CFLAGS=""
|
||||||
|
if test "${LG_SIZEOF_PTR}" = "3"; then
|
||||||
|
default_retain="1"
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
AC_MSG_RESULT([Unsupported operating system: ${host}])
|
AC_MSG_RESULT([Unsupported operating system: ${host}])
|
||||||
@ -786,6 +854,18 @@ if test "x${je_cv_format_printf}" = "xyes" ; then
|
|||||||
AC_DEFINE([JEMALLOC_HAVE_ATTR_FORMAT_PRINTF], [ ])
|
AC_DEFINE([JEMALLOC_HAVE_ATTR_FORMAT_PRINTF], [ ])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
dnl Check for format_arg(...) attribute support.
|
||||||
|
JE_CFLAGS_SAVE()
|
||||||
|
JE_CFLAGS_ADD([-Werror])
|
||||||
|
JE_CFLAGS_ADD([-herror_on_warning])
|
||||||
|
JE_COMPILABLE([format(printf, ...) attribute], [#include <stdlib.h>],
|
||||||
|
[const char * __attribute__((__format_arg__(1))) foo(const char *format);],
|
||||||
|
[je_cv_format_arg])
|
||||||
|
JE_CFLAGS_RESTORE()
|
||||||
|
if test "x${je_cv_format_arg}" = "xyes" ; then
|
||||||
|
AC_DEFINE([JEMALLOC_HAVE_ATTR_FORMAT_ARG], [ ])
|
||||||
|
fi
|
||||||
|
|
||||||
dnl Support optional additions to rpath.
|
dnl Support optional additions to rpath.
|
||||||
AC_ARG_WITH([rpath],
|
AC_ARG_WITH([rpath],
|
||||||
[AS_HELP_STRING([--with-rpath=<rpath>], [Colon-separated rpath (ELF systems only)])],
|
[AS_HELP_STRING([--with-rpath=<rpath>], [Colon-separated rpath (ELF systems only)])],
|
||||||
@ -816,6 +896,49 @@ AC_PROG_RANLIB
|
|||||||
AC_PATH_PROG([LD], [ld], [false], [$PATH])
|
AC_PATH_PROG([LD], [ld], [false], [$PATH])
|
||||||
AC_PATH_PROG([AUTOCONF], [autoconf], [false], [$PATH])
|
AC_PATH_PROG([AUTOCONF], [autoconf], [false], [$PATH])
|
||||||
|
|
||||||
|
dnl Enable documentation
|
||||||
|
AC_ARG_ENABLE([doc],
|
||||||
|
[AS_HELP_STRING([--enable-documentation], [Build documentation])],
|
||||||
|
if test "x$enable_doc" = "xno" ; then
|
||||||
|
enable_doc="0"
|
||||||
|
else
|
||||||
|
enable_doc="1"
|
||||||
|
fi
|
||||||
|
,
|
||||||
|
enable_doc="1"
|
||||||
|
)
|
||||||
|
AC_SUBST([enable_doc])
|
||||||
|
|
||||||
|
dnl Enable shared libs
|
||||||
|
AC_ARG_ENABLE([shared],
|
||||||
|
[AS_HELP_STRING([--enable-shared], [Build shared libaries])],
|
||||||
|
if test "x$enable_shared" = "xno" ; then
|
||||||
|
enable_shared="0"
|
||||||
|
else
|
||||||
|
enable_shared="1"
|
||||||
|
fi
|
||||||
|
,
|
||||||
|
enable_shared="1"
|
||||||
|
)
|
||||||
|
AC_SUBST([enable_shared])
|
||||||
|
|
||||||
|
dnl Enable static libs
|
||||||
|
AC_ARG_ENABLE([static],
|
||||||
|
[AS_HELP_STRING([--enable-static], [Build static libaries])],
|
||||||
|
if test "x$enable_static" = "xno" ; then
|
||||||
|
enable_static="0"
|
||||||
|
else
|
||||||
|
enable_static="1"
|
||||||
|
fi
|
||||||
|
,
|
||||||
|
enable_static="1"
|
||||||
|
)
|
||||||
|
AC_SUBST([enable_static])
|
||||||
|
|
||||||
|
if test "$enable_shared$enable_static" = "00" ; then
|
||||||
|
AC_MSG_ERROR([Please enable one of shared or static builds])
|
||||||
|
fi
|
||||||
|
|
||||||
dnl Perform no name mangling by default.
|
dnl Perform no name mangling by default.
|
||||||
AC_ARG_WITH([mangling],
|
AC_ARG_WITH([mangling],
|
||||||
[AS_HELP_STRING([--with-mangling=<map>], [Mangle symbols in <map>])],
|
[AS_HELP_STRING([--with-mangling=<map>], [Mangle symbols in <map>])],
|
||||||
@ -848,7 +971,7 @@ AC_ARG_WITH([export],
|
|||||||
fi]
|
fi]
|
||||||
)
|
)
|
||||||
|
|
||||||
public_syms="aligned_alloc calloc dallocx free mallctl mallctlbymib mallctlnametomib malloc malloc_conf malloc_message malloc_stats_print malloc_usable_size mallocx nallocx posix_memalign rallocx realloc sallocx sdallocx xallocx"
|
public_syms="aligned_alloc calloc dallocx free mallctl mallctlbymib mallctlnametomib malloc malloc_conf malloc_message malloc_stats_print malloc_usable_size mallocx smallocx_${jemalloc_version_gid} nallocx posix_memalign rallocx realloc sallocx sdallocx xallocx"
|
||||||
dnl Check for additional platform-specific public API functions.
|
dnl Check for additional platform-specific public API functions.
|
||||||
AC_CHECK_FUNC([memalign],
|
AC_CHECK_FUNC([memalign],
|
||||||
[AC_DEFINE([JEMALLOC_OVERRIDE_MEMALIGN], [ ])
|
[AC_DEFINE([JEMALLOC_OVERRIDE_MEMALIGN], [ ])
|
||||||
@ -966,7 +1089,6 @@ cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_symbols.sh"
|
|||||||
cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_namespace.sh"
|
cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_namespace.sh"
|
||||||
cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/public_namespace.sh"
|
cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/public_namespace.sh"
|
||||||
cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/public_unnamespace.sh"
|
cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/public_unnamespace.sh"
|
||||||
cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/size_classes.sh"
|
|
||||||
cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc_rename.sh"
|
cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc_rename.sh"
|
||||||
cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc_mangle.sh"
|
cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc_mangle.sh"
|
||||||
cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc.sh"
|
cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc.sh"
|
||||||
@ -979,7 +1101,6 @@ cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/private_symbols_jet.awk"
|
|||||||
cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_symbols.txt"
|
cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_symbols.txt"
|
||||||
cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_namespace.h"
|
cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_namespace.h"
|
||||||
cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_unnamespace.h"
|
cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_unnamespace.h"
|
||||||
cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/size_classes.h"
|
|
||||||
cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_protos_jet.h"
|
cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_protos_jet.h"
|
||||||
cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_rename.h"
|
cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_rename.h"
|
||||||
cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_mangle.h"
|
cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_mangle.h"
|
||||||
@ -991,6 +1112,10 @@ cfghdrs_tup="include/jemalloc/jemalloc_defs.h:include/jemalloc/jemalloc_defs.h.i
|
|||||||
cfghdrs_tup="${cfghdrs_tup} include/jemalloc/internal/jemalloc_internal_defs.h:include/jemalloc/internal/jemalloc_internal_defs.h.in"
|
cfghdrs_tup="${cfghdrs_tup} include/jemalloc/internal/jemalloc_internal_defs.h:include/jemalloc/internal/jemalloc_internal_defs.h.in"
|
||||||
cfghdrs_tup="${cfghdrs_tup} test/include/test/jemalloc_test_defs.h:test/include/test/jemalloc_test_defs.h.in"
|
cfghdrs_tup="${cfghdrs_tup} test/include/test/jemalloc_test_defs.h:test/include/test/jemalloc_test_defs.h.in"
|
||||||
|
|
||||||
|
dnl ============================================================================
|
||||||
|
dnl jemalloc build options.
|
||||||
|
dnl
|
||||||
|
|
||||||
dnl Do not compile with debugging by default.
|
dnl Do not compile with debugging by default.
|
||||||
AC_ARG_ENABLE([debug],
|
AC_ARG_ENABLE([debug],
|
||||||
[AS_HELP_STRING([--enable-debug],
|
[AS_HELP_STRING([--enable-debug],
|
||||||
@ -1043,6 +1168,22 @@ if test "x$enable_stats" = "x1" ; then
|
|||||||
fi
|
fi
|
||||||
AC_SUBST([enable_stats])
|
AC_SUBST([enable_stats])
|
||||||
|
|
||||||
|
dnl Do not enable smallocx by default.
|
||||||
|
AC_ARG_ENABLE([experimental_smallocx],
|
||||||
|
[AS_HELP_STRING([--enable-experimental-smallocx], [Enable experimental smallocx API])],
|
||||||
|
[if test "x$enable_experimental_smallocx" = "xno" ; then
|
||||||
|
enable_experimental_smallocx="0"
|
||||||
|
else
|
||||||
|
enable_experimental_smallocx="1"
|
||||||
|
fi
|
||||||
|
],
|
||||||
|
[enable_experimental_smallocx="0"]
|
||||||
|
)
|
||||||
|
if test "x$enable_experimental_smallocx" = "x1" ; then
|
||||||
|
AC_DEFINE([JEMALLOC_EXPERIMENTAL_SMALLOCX_API])
|
||||||
|
fi
|
||||||
|
AC_SUBST([enable_experimental_smallocx])
|
||||||
|
|
||||||
dnl Do not enable profiling by default.
|
dnl Do not enable profiling by default.
|
||||||
AC_ARG_ENABLE([prof],
|
AC_ARG_ENABLE([prof],
|
||||||
[AS_HELP_STRING([--enable-prof], [Enable allocation profiling])],
|
[AS_HELP_STRING([--enable-prof], [Enable allocation profiling])],
|
||||||
@ -1277,6 +1418,38 @@ if test "x$enable_log" = "x1" ; then
|
|||||||
fi
|
fi
|
||||||
AC_SUBST([enable_log])
|
AC_SUBST([enable_log])
|
||||||
|
|
||||||
|
dnl Do not use readlinkat by default
|
||||||
|
AC_ARG_ENABLE([readlinkat],
|
||||||
|
[AS_HELP_STRING([--enable-readlinkat], [Use readlinkat over readlink])],
|
||||||
|
[if test "x$enable_readlinkat" = "xno" ; then
|
||||||
|
enable_readlinkat="0"
|
||||||
|
else
|
||||||
|
enable_readlinkat="1"
|
||||||
|
fi
|
||||||
|
],
|
||||||
|
[enable_readlinkat="0"]
|
||||||
|
)
|
||||||
|
if test "x$enable_readlinkat" = "x1" ; then
|
||||||
|
AC_DEFINE([JEMALLOC_READLINKAT], [ ])
|
||||||
|
fi
|
||||||
|
AC_SUBST([enable_readlinkat])
|
||||||
|
|
||||||
|
dnl Avoid extra safety checks by default
|
||||||
|
AC_ARG_ENABLE([opt-safety-checks],
|
||||||
|
[AS_HELP_STRING([--enable-opt-safety-checks],
|
||||||
|
[Perform certain low-overhead checks, even in opt mode])],
|
||||||
|
[if test "x$enable_opt_safety_checks" = "xno" ; then
|
||||||
|
enable_opt_safety_checks="0"
|
||||||
|
else
|
||||||
|
enable_opt_safety_checks="1"
|
||||||
|
fi
|
||||||
|
],
|
||||||
|
[enable_opt_safety_checks="0"]
|
||||||
|
)
|
||||||
|
if test "x$enable_opt_safety_checks" = "x1" ; then
|
||||||
|
AC_DEFINE([JEMALLOC_OPT_SAFETY_CHECKS], [ ])
|
||||||
|
fi
|
||||||
|
AC_SUBST([enable_opt_safety_checks])
|
||||||
|
|
||||||
JE_COMPILABLE([a program using __builtin_unreachable], [
|
JE_COMPILABLE([a program using __builtin_unreachable], [
|
||||||
void foo (void) {
|
void foo (void) {
|
||||||
@ -1333,6 +1506,21 @@ else
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
JE_COMPILABLE([a program using __builtin_popcountl], [
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include <string.h>
|
||||||
|
], [
|
||||||
|
{
|
||||||
|
int rv = __builtin_popcountl(0x08);
|
||||||
|
printf("%d\n", rv);
|
||||||
|
}
|
||||||
|
], [je_cv_gcc_builtin_popcountl])
|
||||||
|
if test "x${je_cv_gcc_builtin_popcountl}" = "xyes" ; then
|
||||||
|
AC_DEFINE([JEMALLOC_INTERNAL_POPCOUNT], [__builtin_popcount])
|
||||||
|
AC_DEFINE([JEMALLOC_INTERNAL_POPCOUNTL], [__builtin_popcountl])
|
||||||
|
fi
|
||||||
|
|
||||||
AC_ARG_WITH([lg_quantum],
|
AC_ARG_WITH([lg_quantum],
|
||||||
[AS_HELP_STRING([--with-lg-quantum=<lg-quantum>],
|
[AS_HELP_STRING([--with-lg-quantum=<lg-quantum>],
|
||||||
[Base 2 log of minimum allocation alignment])],
|
[Base 2 log of minimum allocation alignment])],
|
||||||
@ -1430,70 +1618,20 @@ if test "x${LG_PAGE}" != "xundefined" -a \
|
|||||||
fi
|
fi
|
||||||
AC_DEFINE_UNQUOTED([LG_HUGEPAGE], [${je_cv_lg_hugepage}])
|
AC_DEFINE_UNQUOTED([LG_HUGEPAGE], [${je_cv_lg_hugepage}])
|
||||||
|
|
||||||
AC_ARG_WITH([lg_page_sizes],
|
|
||||||
[AS_HELP_STRING([--with-lg-page-sizes=<lg-page-sizes>],
|
|
||||||
[Base 2 logs of system page sizes to support])],
|
|
||||||
[LG_PAGE_SIZES="$with_lg_page_sizes"], [LG_PAGE_SIZES="$LG_PAGE"])
|
|
||||||
|
|
||||||
dnl ============================================================================
|
dnl ============================================================================
|
||||||
dnl jemalloc configuration.
|
dnl Enable libdl by default.
|
||||||
dnl
|
AC_ARG_ENABLE([libdl],
|
||||||
|
[AS_HELP_STRING([--disable-libdl],
|
||||||
AC_ARG_WITH([version],
|
[Do not use libdl])],
|
||||||
[AS_HELP_STRING([--with-version=<major>.<minor>.<bugfix>-<nrev>-g<gid>],
|
[if test "x$enable_libdl" = "xno" ; then
|
||||||
[Version string])],
|
enable_libdl="0"
|
||||||
[
|
|
||||||
echo "${with_version}" | grep ['^[0-9]\+\.[0-9]\+\.[0-9]\+-[0-9]\+-g[0-9a-f]\+$'] 2>&1 1>/dev/null
|
|
||||||
if test $? -eq 0 ; then
|
|
||||||
echo "$with_version" > "${objroot}VERSION"
|
|
||||||
else
|
else
|
||||||
echo "${with_version}" | grep ['^VERSION$'] 2>&1 1>/dev/null
|
enable_libdl="1"
|
||||||
if test $? -ne 0 ; then
|
|
||||||
AC_MSG_ERROR([${with_version} does not match <major>.<minor>.<bugfix>-<nrev>-g<gid> or VERSION])
|
|
||||||
fi
|
fi
|
||||||
fi
|
],
|
||||||
], [
|
[enable_libdl="1"]
|
||||||
dnl Set VERSION if source directory is inside a git repository.
|
)
|
||||||
if test "x`test ! \"${srcroot}\" && cd \"${srcroot}\"; git rev-parse --is-inside-work-tree 2>/dev/null`" = "xtrue" ; then
|
AC_SUBST([libdl])
|
||||||
dnl Pattern globs aren't powerful enough to match both single- and
|
|
||||||
dnl double-digit version numbers, so iterate over patterns to support up
|
|
||||||
dnl to version 99.99.99 without any accidental matches.
|
|
||||||
for pattern in ['[0-9].[0-9].[0-9]' '[0-9].[0-9].[0-9][0-9]' \
|
|
||||||
'[0-9].[0-9][0-9].[0-9]' '[0-9].[0-9][0-9].[0-9][0-9]' \
|
|
||||||
'[0-9][0-9].[0-9].[0-9]' '[0-9][0-9].[0-9].[0-9][0-9]' \
|
|
||||||
'[0-9][0-9].[0-9][0-9].[0-9]' \
|
|
||||||
'[0-9][0-9].[0-9][0-9].[0-9][0-9]']; do
|
|
||||||
(test ! "${srcroot}" && cd "${srcroot}"; git describe --long --abbrev=40 --match="${pattern}") > "${objroot}VERSION.tmp" 2>/dev/null
|
|
||||||
if test $? -eq 0 ; then
|
|
||||||
mv "${objroot}VERSION.tmp" "${objroot}VERSION"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
rm -f "${objroot}VERSION.tmp"
|
|
||||||
])
|
|
||||||
|
|
||||||
if test ! -e "${objroot}VERSION" ; then
|
|
||||||
if test ! -e "${srcroot}VERSION" ; then
|
|
||||||
AC_MSG_RESULT(
|
|
||||||
[Missing VERSION file, and unable to generate it; creating bogus VERSION])
|
|
||||||
echo "0.0.0-0-g0000000000000000000000000000000000000000" > "${objroot}VERSION"
|
|
||||||
else
|
|
||||||
cp ${srcroot}VERSION ${objroot}VERSION
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
jemalloc_version=`cat "${objroot}VERSION"`
|
|
||||||
jemalloc_version_major=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]1}'`
|
|
||||||
jemalloc_version_minor=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]2}'`
|
|
||||||
jemalloc_version_bugfix=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]3}'`
|
|
||||||
jemalloc_version_nrev=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]4}'`
|
|
||||||
jemalloc_version_gid=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]5}'`
|
|
||||||
AC_SUBST([jemalloc_version])
|
|
||||||
AC_SUBST([jemalloc_version_major])
|
|
||||||
AC_SUBST([jemalloc_version_minor])
|
|
||||||
AC_SUBST([jemalloc_version_bugfix])
|
|
||||||
AC_SUBST([jemalloc_version_nrev])
|
|
||||||
AC_SUBST([jemalloc_version_gid])
|
|
||||||
|
|
||||||
dnl ============================================================================
|
dnl ============================================================================
|
||||||
dnl Configure pthreads.
|
dnl Configure pthreads.
|
||||||
@ -1503,12 +1641,14 @@ if test "x$abi" != "xpecoff" ; then
|
|||||||
AC_CHECK_HEADERS([pthread.h], , [AC_MSG_ERROR([pthread.h is missing])])
|
AC_CHECK_HEADERS([pthread.h], , [AC_MSG_ERROR([pthread.h is missing])])
|
||||||
dnl Some systems may embed pthreads functionality in libc; check for libpthread
|
dnl Some systems may embed pthreads functionality in libc; check for libpthread
|
||||||
dnl first, but try libc too before failing.
|
dnl first, but try libc too before failing.
|
||||||
AC_CHECK_LIB([pthread], [pthread_create], [JE_APPEND_VS(LIBS, -lpthread)],
|
AC_CHECK_LIB([pthread], [pthread_create], [JE_APPEND_VS(LIBS, -pthread)],
|
||||||
[AC_SEARCH_LIBS([pthread_create], , ,
|
[AC_SEARCH_LIBS([pthread_create], , ,
|
||||||
AC_MSG_ERROR([libpthread is missing]))])
|
AC_MSG_ERROR([libpthread is missing]))])
|
||||||
wrap_syms="${wrap_syms} pthread_create"
|
wrap_syms="${wrap_syms} pthread_create"
|
||||||
have_pthread="1"
|
have_pthread="1"
|
||||||
|
|
||||||
dnl Check if we have dlsym support.
|
dnl Check if we have dlsym support.
|
||||||
|
if test "x$enable_libdl" = "x1" ; then
|
||||||
have_dlsym="1"
|
have_dlsym="1"
|
||||||
AC_CHECK_HEADERS([dlfcn.h],
|
AC_CHECK_HEADERS([dlfcn.h],
|
||||||
AC_CHECK_FUNC([dlsym], [],
|
AC_CHECK_FUNC([dlsym], [],
|
||||||
@ -1517,6 +1657,10 @@ if test "x$abi" != "xpecoff" ; then
|
|||||||
if test "x$have_dlsym" = "x1" ; then
|
if test "x$have_dlsym" = "x1" ; then
|
||||||
AC_DEFINE([JEMALLOC_HAVE_DLSYM], [ ])
|
AC_DEFINE([JEMALLOC_HAVE_DLSYM], [ ])
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
|
have_dlsym="0"
|
||||||
|
fi
|
||||||
|
|
||||||
JE_COMPILABLE([pthread_atfork(3)], [
|
JE_COMPILABLE([pthread_atfork(3)], [
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
], [
|
], [
|
||||||
@ -1780,6 +1924,19 @@ JE_COMPILABLE([GCC __atomic atomics], [
|
|||||||
], [je_cv_gcc_atomic_atomics])
|
], [je_cv_gcc_atomic_atomics])
|
||||||
if test "x${je_cv_gcc_atomic_atomics}" = "xyes" ; then
|
if test "x${je_cv_gcc_atomic_atomics}" = "xyes" ; then
|
||||||
AC_DEFINE([JEMALLOC_GCC_ATOMIC_ATOMICS])
|
AC_DEFINE([JEMALLOC_GCC_ATOMIC_ATOMICS])
|
||||||
|
|
||||||
|
dnl check for 8-bit atomic support
|
||||||
|
JE_COMPILABLE([GCC 8-bit __atomic atomics], [
|
||||||
|
], [
|
||||||
|
unsigned char x = 0;
|
||||||
|
int val = 1;
|
||||||
|
int y = __atomic_fetch_add(&x, val, __ATOMIC_RELAXED);
|
||||||
|
int after_add = (int)x;
|
||||||
|
return after_add == 1;
|
||||||
|
], [je_cv_gcc_u8_atomic_atomics])
|
||||||
|
if test "x${je_cv_gcc_u8_atomic_atomics}" = "xyes" ; then
|
||||||
|
AC_DEFINE([JEMALLOC_GCC_U8_ATOMIC_ATOMICS])
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dnl ============================================================================
|
dnl ============================================================================
|
||||||
@ -1794,12 +1951,24 @@ JE_COMPILABLE([GCC __sync atomics], [
|
|||||||
], [je_cv_gcc_sync_atomics])
|
], [je_cv_gcc_sync_atomics])
|
||||||
if test "x${je_cv_gcc_sync_atomics}" = "xyes" ; then
|
if test "x${je_cv_gcc_sync_atomics}" = "xyes" ; then
|
||||||
AC_DEFINE([JEMALLOC_GCC_SYNC_ATOMICS])
|
AC_DEFINE([JEMALLOC_GCC_SYNC_ATOMICS])
|
||||||
|
|
||||||
|
dnl check for 8-bit atomic support
|
||||||
|
JE_COMPILABLE([GCC 8-bit __sync atomics], [
|
||||||
|
], [
|
||||||
|
unsigned char x = 0;
|
||||||
|
int before_add = __sync_fetch_and_add(&x, 1);
|
||||||
|
int after_add = (int)x;
|
||||||
|
return (before_add == 0) && (after_add == 1);
|
||||||
|
], [je_cv_gcc_u8_sync_atomics])
|
||||||
|
if test "x${je_cv_gcc_u8_sync_atomics}" = "xyes" ; then
|
||||||
|
AC_DEFINE([JEMALLOC_GCC_U8_SYNC_ATOMICS])
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dnl ============================================================================
|
dnl ============================================================================
|
||||||
dnl Check for atomic(3) operations as provided on Darwin.
|
dnl Check for atomic(3) operations as provided on Darwin.
|
||||||
dnl We need this not for the atomic operations (which are provided above), but
|
dnl We need this not for the atomic operations (which are provided above), but
|
||||||
dnl rather for the OSSpinLock type it exposes.
|
dnl rather for the OS_unfair_lock type it exposes.
|
||||||
|
|
||||||
JE_COMPILABLE([Darwin OSAtomic*()], [
|
JE_COMPILABLE([Darwin OSAtomic*()], [
|
||||||
#include <libkern/OSAtomic.h>
|
#include <libkern/OSAtomic.h>
|
||||||
@ -1889,40 +2058,6 @@ case "${host_cpu}" in
|
|||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dnl ============================================================================
|
|
||||||
dnl Check whether __sync_{add,sub}_and_fetch() are available despite
|
|
||||||
dnl __GCC_HAVE_SYNC_COMPARE_AND_SWAP_n macros being undefined.
|
|
||||||
|
|
||||||
AC_DEFUN([JE_SYNC_COMPARE_AND_SWAP_CHECK],[
|
|
||||||
AC_CACHE_CHECK([whether to force $1-bit __sync_{add,sub}_and_fetch()],
|
|
||||||
[je_cv_sync_compare_and_swap_$2],
|
|
||||||
[AC_LINK_IFELSE([AC_LANG_PROGRAM([
|
|
||||||
#include <stdint.h>
|
|
||||||
],
|
|
||||||
[
|
|
||||||
#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_$2
|
|
||||||
{
|
|
||||||
uint$1_t x$1 = 0;
|
|
||||||
__sync_add_and_fetch(&x$1, 42);
|
|
||||||
__sync_sub_and_fetch(&x$1, 1);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#error __GCC_HAVE_SYNC_COMPARE_AND_SWAP_$2 is defined, no need to force
|
|
||||||
#endif
|
|
||||||
])],
|
|
||||||
[je_cv_sync_compare_and_swap_$2=yes],
|
|
||||||
[je_cv_sync_compare_and_swap_$2=no])])
|
|
||||||
|
|
||||||
if test "x${je_cv_sync_compare_and_swap_$2}" = "xyes" ; then
|
|
||||||
AC_DEFINE([JE_FORCE_SYNC_COMPARE_AND_SWAP_$2], [ ])
|
|
||||||
fi
|
|
||||||
])
|
|
||||||
|
|
||||||
if test "x${je_cv_atomic9}" != "xyes" -a "x${je_cv_osatomic}" != "xyes" ; then
|
|
||||||
JE_SYNC_COMPARE_AND_SWAP_CHECK(32, 4)
|
|
||||||
JE_SYNC_COMPARE_AND_SWAP_CHECK(64, 8)
|
|
||||||
fi
|
|
||||||
|
|
||||||
dnl ============================================================================
|
dnl ============================================================================
|
||||||
dnl Check for __builtin_clz() and __builtin_clzl().
|
dnl Check for __builtin_clz() and __builtin_clzl().
|
||||||
|
|
||||||
@ -1965,21 +2100,6 @@ if test "x${je_cv_os_unfair_lock}" = "xyes" ; then
|
|||||||
AC_DEFINE([JEMALLOC_OS_UNFAIR_LOCK], [ ])
|
AC_DEFINE([JEMALLOC_OS_UNFAIR_LOCK], [ ])
|
||||||
fi
|
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);
|
|
||||||
], [je_cv_osspin])
|
|
||||||
if test "x${je_cv_osspin}" = "xyes" ; then
|
|
||||||
AC_DEFINE([JEMALLOC_OSSPIN], [ ])
|
|
||||||
fi
|
|
||||||
|
|
||||||
dnl ============================================================================
|
dnl ============================================================================
|
||||||
dnl Darwin-related configuration.
|
dnl Darwin-related configuration.
|
||||||
|
|
||||||
@ -2032,9 +2152,7 @@ fi
|
|||||||
dnl ============================================================================
|
dnl ============================================================================
|
||||||
dnl Enable background threads if possible.
|
dnl Enable background threads if possible.
|
||||||
|
|
||||||
if test "x${have_pthread}" = "x1" -a "x${have_dlsym}" = "x1" \
|
if test "x${have_pthread}" = "x1" -a "x${je_cv_os_unfair_lock}" != "xyes" ; then
|
||||||
-a "x${je_cv_os_unfair_lock}" != "xyes" \
|
|
||||||
-a "x${je_cv_osspin}" != "xyes" ; then
|
|
||||||
AC_DEFINE([JEMALLOC_BACKGROUND_THREAD])
|
AC_DEFINE([JEMALLOC_BACKGROUND_THREAD])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -2175,16 +2293,6 @@ AC_CONFIG_COMMANDS([include/jemalloc/internal/public_unnamespace.h], [
|
|||||||
srcdir="${srcdir}"
|
srcdir="${srcdir}"
|
||||||
objroot="${objroot}"
|
objroot="${objroot}"
|
||||||
])
|
])
|
||||||
AC_CONFIG_COMMANDS([include/jemalloc/internal/size_classes.h], [
|
|
||||||
mkdir -p "${objroot}include/jemalloc/internal"
|
|
||||||
"${SHELL}" "${srcdir}/include/jemalloc/internal/size_classes.sh" "${LG_QUANTA}" 3 "${LG_PAGE_SIZES}" 2 > "${objroot}include/jemalloc/internal/size_classes.h"
|
|
||||||
], [
|
|
||||||
SHELL="${SHELL}"
|
|
||||||
srcdir="${srcdir}"
|
|
||||||
objroot="${objroot}"
|
|
||||||
LG_QUANTA="${LG_QUANTA}"
|
|
||||||
LG_PAGE_SIZES="${LG_PAGE_SIZES}"
|
|
||||||
])
|
|
||||||
AC_CONFIG_COMMANDS([include/jemalloc/jemalloc_protos_jet.h], [
|
AC_CONFIG_COMMANDS([include/jemalloc/jemalloc_protos_jet.h], [
|
||||||
mkdir -p "${objroot}include/jemalloc"
|
mkdir -p "${objroot}include/jemalloc"
|
||||||
cat "${srcdir}/include/jemalloc/jemalloc_protos.h.in" | sed -e 's/@je_@/jet_/g' > "${objroot}include/jemalloc/jemalloc_protos_jet.h"
|
cat "${srcdir}/include/jemalloc/jemalloc_protos.h.in" | sed -e 's/@je_@/jet_/g' > "${objroot}include/jemalloc/jemalloc_protos_jet.h"
|
||||||
@ -2277,9 +2385,13 @@ AC_MSG_RESULT([JEMALLOC_PRIVATE_NAMESPACE])
|
|||||||
AC_MSG_RESULT([ : ${JEMALLOC_PRIVATE_NAMESPACE}])
|
AC_MSG_RESULT([ : ${JEMALLOC_PRIVATE_NAMESPACE}])
|
||||||
AC_MSG_RESULT([install_suffix : ${install_suffix}])
|
AC_MSG_RESULT([install_suffix : ${install_suffix}])
|
||||||
AC_MSG_RESULT([malloc_conf : ${config_malloc_conf}])
|
AC_MSG_RESULT([malloc_conf : ${config_malloc_conf}])
|
||||||
|
AC_MSG_RESULT([documentation : ${enable_doc}])
|
||||||
|
AC_MSG_RESULT([shared libs : ${enable_shared}])
|
||||||
|
AC_MSG_RESULT([static libs : ${enable_static}])
|
||||||
AC_MSG_RESULT([autogen : ${enable_autogen}])
|
AC_MSG_RESULT([autogen : ${enable_autogen}])
|
||||||
AC_MSG_RESULT([debug : ${enable_debug}])
|
AC_MSG_RESULT([debug : ${enable_debug}])
|
||||||
AC_MSG_RESULT([stats : ${enable_stats}])
|
AC_MSG_RESULT([stats : ${enable_stats}])
|
||||||
|
AC_MSG_RESULT([experimetal_smallocx : ${enable_experimental_smallocx}])
|
||||||
AC_MSG_RESULT([prof : ${enable_prof}])
|
AC_MSG_RESULT([prof : ${enable_prof}])
|
||||||
AC_MSG_RESULT([prof-libunwind : ${enable_prof_libunwind}])
|
AC_MSG_RESULT([prof-libunwind : ${enable_prof_libunwind}])
|
||||||
AC_MSG_RESULT([prof-libgcc : ${enable_prof_libgcc}])
|
AC_MSG_RESULT([prof-libgcc : ${enable_prof_libgcc}])
|
||||||
|
178
deps/jemalloc/doc/jemalloc.xml.in
vendored
178
deps/jemalloc/doc/jemalloc.xml.in
vendored
@ -424,7 +424,7 @@ for (i = 0; i < nbins; i++) {
|
|||||||
called repeatedly. General information that never changes during
|
called repeatedly. General information that never changes during
|
||||||
execution can be omitted by specifying <quote>g</quote> as a character
|
execution can be omitted by specifying <quote>g</quote> as a character
|
||||||
within the <parameter>opts</parameter> string. Note that
|
within the <parameter>opts</parameter> string. Note that
|
||||||
<function>malloc_message()</function> uses the
|
<function>malloc_stats_print()</function> uses the
|
||||||
<function>mallctl*()</function> functions internally, so inconsistent
|
<function>mallctl*()</function> functions internally, so inconsistent
|
||||||
statistics can be reported if multiple threads use these functions
|
statistics can be reported if multiple threads use these functions
|
||||||
simultaneously. If <option>--enable-stats</option> is specified during
|
simultaneously. If <option>--enable-stats</option> is specified during
|
||||||
@ -433,10 +433,11 @@ for (i = 0; i < nbins; i++) {
|
|||||||
arena statistics, respectively; <quote>b</quote> and <quote>l</quote> can
|
arena statistics, respectively; <quote>b</quote> and <quote>l</quote> can
|
||||||
be specified to omit per size class statistics for bins and large objects,
|
be specified to omit per size class statistics for bins and large objects,
|
||||||
respectively; <quote>x</quote> can be specified to omit all mutex
|
respectively; <quote>x</quote> can be specified to omit all mutex
|
||||||
statistics. Unrecognized characters are silently ignored. Note that
|
statistics; <quote>e</quote> can be used to omit extent statistics.
|
||||||
thread caching may prevent some statistics from being completely up to
|
Unrecognized characters are silently ignored. Note that thread caching
|
||||||
date, since extra locking would be required to merge counters that track
|
may prevent some statistics from being completely up to date, since extra
|
||||||
thread cache operations.</para>
|
locking would be required to merge counters that track thread cache
|
||||||
|
operations.</para>
|
||||||
|
|
||||||
<para>The <function>malloc_usable_size()</function> function
|
<para>The <function>malloc_usable_size()</function> function
|
||||||
returns the usable size of the allocation pointed to by
|
returns the usable size of the allocation pointed to by
|
||||||
@ -903,6 +904,23 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay",
|
|||||||
</para></listitem>
|
</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="opt.confirm_conf">
|
||||||
|
<term>
|
||||||
|
<mallctl>opt.confirm_conf</mallctl>
|
||||||
|
(<type>bool</type>)
|
||||||
|
<literal>r-</literal>
|
||||||
|
</term>
|
||||||
|
<listitem><para>Confirm-runtime-options-when-program-starts
|
||||||
|
enabled/disabled. If true, the string specified via
|
||||||
|
<option>--with-malloc-conf</option>, the string pointed to by the
|
||||||
|
global variable <varname>malloc_conf</varname>, the <quote>name</quote>
|
||||||
|
of the file referenced by the symbolic link named
|
||||||
|
<filename class="symlink">/etc/malloc.conf</filename>, and the value of
|
||||||
|
the environment variable <envar>MALLOC_CONF</envar>, will be printed in
|
||||||
|
order. Then, each option being set will be individually printed. This
|
||||||
|
option is disabled by default.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry id="opt.abort_conf">
|
<varlistentry id="opt.abort_conf">
|
||||||
<term>
|
<term>
|
||||||
<mallctl>opt.abort_conf</mallctl>
|
<mallctl>opt.abort_conf</mallctl>
|
||||||
@ -943,16 +961,19 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay",
|
|||||||
<citerefentry><refentrytitle>munmap</refentrytitle>
|
<citerefentry><refentrytitle>munmap</refentrytitle>
|
||||||
<manvolnum>2</manvolnum></citerefentry> or equivalent (see <link
|
<manvolnum>2</manvolnum></citerefentry> or equivalent (see <link
|
||||||
linkend="stats.retained">stats.retained</link> for related details).
|
linkend="stats.retained">stats.retained</link> for related details).
|
||||||
This option is disabled by default unless discarding virtual memory is
|
It also makes jemalloc use <citerefentry>
|
||||||
known to trigger
|
<refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum>
|
||||||
platform-specific performance problems, e.g. for [64-bit] Linux, which
|
</citerefentry> or equivalent in a more greedy way, mapping larger
|
||||||
has a quirk in its virtual memory allocation algorithm that causes
|
chunks in one go. This option is disabled by default unless discarding
|
||||||
semi-permanent VM map holes under normal jemalloc operation. Although
|
virtual memory is known to trigger platform-specific performance
|
||||||
<citerefentry><refentrytitle>munmap</refentrytitle>
|
problems, namely 1) for [64-bit] Linux, which has a quirk in its virtual
|
||||||
<manvolnum>2</manvolnum></citerefentry> causes issues on 32-bit Linux as
|
memory allocation algorithm that causes semi-permanent VM map holes
|
||||||
well, retaining virtual memory for 32-bit Linux is disabled by default
|
under normal jemalloc operation; and 2) for [64-bit] Windows, which
|
||||||
due to the practical possibility of address space exhaustion.
|
disallows split / merged regions with
|
||||||
</para></listitem>
|
<parameter><constant>MEM_RELEASE</constant></parameter>. Although the
|
||||||
|
same issues may present on 32-bit platforms as well, retaining virtual
|
||||||
|
memory for 32-bit Linux and Windows is disabled by default due to the
|
||||||
|
practical possibility of address space exhaustion. </para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry id="opt.dss">
|
<varlistentry id="opt.dss">
|
||||||
@ -988,6 +1009,24 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay",
|
|||||||
number of CPUs, or one if there is a single CPU.</para></listitem>
|
number of CPUs, or one if there is a single CPU.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="opt.oversize_threshold">
|
||||||
|
<term>
|
||||||
|
<mallctl>opt.oversize_threshold</mallctl>
|
||||||
|
(<type>size_t</type>)
|
||||||
|
<literal>r-</literal>
|
||||||
|
</term>
|
||||||
|
<listitem><para>The threshold in bytes of which requests are considered
|
||||||
|
oversize. Allocation requests with greater sizes are fulfilled from a
|
||||||
|
dedicated arena (automatically managed, however not within
|
||||||
|
<literal>narenas</literal>), in order to reduce fragmentation by not
|
||||||
|
mixing huge allocations with small ones. In addition, the decay API
|
||||||
|
guarantees on the extents greater than the specified threshold may be
|
||||||
|
overridden. Note that requests with arena index specified via
|
||||||
|
<constant>MALLOCX_ARENA</constant>, or threads associated with explicit
|
||||||
|
arenas will not be considered. The default threshold is 8MiB. Values
|
||||||
|
not within large size classes disables this feature.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry id="opt.percpu_arena">
|
<varlistentry id="opt.percpu_arena">
|
||||||
<term>
|
<term>
|
||||||
<mallctl>opt.percpu_arena</mallctl>
|
<mallctl>opt.percpu_arena</mallctl>
|
||||||
@ -1009,7 +1048,7 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay",
|
|||||||
<varlistentry id="opt.background_thread">
|
<varlistentry id="opt.background_thread">
|
||||||
<term>
|
<term>
|
||||||
<mallctl>opt.background_thread</mallctl>
|
<mallctl>opt.background_thread</mallctl>
|
||||||
(<type>const bool</type>)
|
(<type>bool</type>)
|
||||||
<literal>r-</literal>
|
<literal>r-</literal>
|
||||||
</term>
|
</term>
|
||||||
<listitem><para>Internal background worker threads enabled/disabled.
|
<listitem><para>Internal background worker threads enabled/disabled.
|
||||||
@ -1024,7 +1063,7 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay",
|
|||||||
<varlistentry id="opt.max_background_threads">
|
<varlistentry id="opt.max_background_threads">
|
||||||
<term>
|
<term>
|
||||||
<mallctl>opt.max_background_threads</mallctl>
|
<mallctl>opt.max_background_threads</mallctl>
|
||||||
(<type>const size_t</type>)
|
(<type>size_t</type>)
|
||||||
<literal>r-</literal>
|
<literal>r-</literal>
|
||||||
</term>
|
</term>
|
||||||
<listitem><para>Maximum number of background threads that will be created
|
<listitem><para>Maximum number of background threads that will be created
|
||||||
@ -1055,7 +1094,11 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay",
|
|||||||
linkend="arena.i.dirty_decay_ms"><mallctl>arena.<i>.dirty_decay_ms</mallctl></link>
|
linkend="arena.i.dirty_decay_ms"><mallctl>arena.<i>.dirty_decay_ms</mallctl></link>
|
||||||
for related dynamic control options. See <link
|
for related dynamic control options. See <link
|
||||||
linkend="opt.muzzy_decay_ms"><mallctl>opt.muzzy_decay_ms</mallctl></link>
|
linkend="opt.muzzy_decay_ms"><mallctl>opt.muzzy_decay_ms</mallctl></link>
|
||||||
for a description of muzzy pages.</para></listitem>
|
for a description of muzzy pages.for a description of muzzy pages. Note
|
||||||
|
that when the <link
|
||||||
|
linkend="opt.oversize_threshold"><mallctl>oversize_threshold</mallctl></link>
|
||||||
|
feature is enabled, the arenas reserved for oversize requests may have
|
||||||
|
its own default decay settings.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry id="opt.muzzy_decay_ms">
|
<varlistentry id="opt.muzzy_decay_ms">
|
||||||
@ -1763,10 +1806,11 @@ malloc_conf = "xmalloc:true";]]></programlisting>
|
|||||||
to control allocation for arenas explicitly created via <link
|
to control allocation for arenas explicitly created via <link
|
||||||
linkend="arenas.create"><mallctl>arenas.create</mallctl></link> such
|
linkend="arenas.create"><mallctl>arenas.create</mallctl></link> such
|
||||||
that all extents originate from an application-supplied extent allocator
|
that all extents originate from an application-supplied extent allocator
|
||||||
(by specifying the custom extent hook functions during arena creation),
|
(by specifying the custom extent hook functions during arena creation).
|
||||||
but the automatically created arenas will have already created extents
|
However, the API guarantees for the automatically created arenas may be
|
||||||
prior to the application having an opportunity to take over extent
|
relaxed -- hooks set there may be called in a "best effort" fashion; in
|
||||||
allocation.</para>
|
addition there may be extents created prior to the application having an
|
||||||
|
opportunity to take over extent allocation.</para>
|
||||||
|
|
||||||
<programlisting language="C"><![CDATA[
|
<programlisting language="C"><![CDATA[
|
||||||
typedef extent_hooks_s extent_hooks_t;
|
typedef extent_hooks_s extent_hooks_t;
|
||||||
@ -2593,6 +2637,17 @@ struct extent_hooks_s {
|
|||||||
details.</para></listitem>
|
details.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="stats.arenas.i.extent_avail">
|
||||||
|
<term>
|
||||||
|
<mallctl>stats.arenas.<i>.extent_avail</mallctl>
|
||||||
|
(<type>size_t</type>)
|
||||||
|
<literal>r-</literal>
|
||||||
|
[<option>--enable-stats</option>]
|
||||||
|
</term>
|
||||||
|
<listitem><para>Number of allocated (but unused) extent structs in this
|
||||||
|
arena.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry id="stats.arenas.i.base">
|
<varlistentry id="stats.arenas.i.base">
|
||||||
<term>
|
<term>
|
||||||
<mallctl>stats.arenas.<i>.base</mallctl>
|
<mallctl>stats.arenas.<i>.base</mallctl>
|
||||||
@ -2760,6 +2815,28 @@ struct extent_hooks_s {
|
|||||||
all bin size classes.</para></listitem>
|
all bin size classes.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="stats.arenas.i.small.nfills">
|
||||||
|
<term>
|
||||||
|
<mallctl>stats.arenas.<i>.small.nfills</mallctl>
|
||||||
|
(<type>uint64_t</type>)
|
||||||
|
<literal>r-</literal>
|
||||||
|
[<option>--enable-stats</option>]
|
||||||
|
</term>
|
||||||
|
<listitem><para>Cumulative number of tcache fills by all small size
|
||||||
|
classes.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="stats.arenas.i.small.nflushes">
|
||||||
|
<term>
|
||||||
|
<mallctl>stats.arenas.<i>.small.nflushes</mallctl>
|
||||||
|
(<type>uint64_t</type>)
|
||||||
|
<literal>r-</literal>
|
||||||
|
[<option>--enable-stats</option>]
|
||||||
|
</term>
|
||||||
|
<listitem><para>Cumulative number of tcache flushes by all small size
|
||||||
|
classes.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry id="stats.arenas.i.large.allocated">
|
<varlistentry id="stats.arenas.i.large.allocated">
|
||||||
<term>
|
<term>
|
||||||
<mallctl>stats.arenas.<i>.large.allocated</mallctl>
|
<mallctl>stats.arenas.<i>.large.allocated</mallctl>
|
||||||
@ -2810,6 +2887,28 @@ struct extent_hooks_s {
|
|||||||
all large size classes.</para></listitem>
|
all large size classes.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="stats.arenas.i.large.nfills">
|
||||||
|
<term>
|
||||||
|
<mallctl>stats.arenas.<i>.large.nfills</mallctl>
|
||||||
|
(<type>uint64_t</type>)
|
||||||
|
<literal>r-</literal>
|
||||||
|
[<option>--enable-stats</option>]
|
||||||
|
</term>
|
||||||
|
<listitem><para>Cumulative number of tcache fills by all large size
|
||||||
|
classes.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="stats.arenas.i.large.nflushes">
|
||||||
|
<term>
|
||||||
|
<mallctl>stats.arenas.<i>.large.nflushes</mallctl>
|
||||||
|
(<type>uint64_t</type>)
|
||||||
|
<literal>r-</literal>
|
||||||
|
[<option>--enable-stats</option>]
|
||||||
|
</term>
|
||||||
|
<listitem><para>Cumulative number of tcache flushes by all large size
|
||||||
|
classes.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry id="stats.arenas.i.bins.j.nmalloc">
|
<varlistentry id="stats.arenas.i.bins.j.nmalloc">
|
||||||
<term>
|
<term>
|
||||||
<mallctl>stats.arenas.<i>.bins.<j>.nmalloc</mallctl>
|
<mallctl>stats.arenas.<i>.bins.<j>.nmalloc</mallctl>
|
||||||
@ -2909,6 +3008,17 @@ struct extent_hooks_s {
|
|||||||
<listitem><para>Current number of slabs.</para></listitem>
|
<listitem><para>Current number of slabs.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
|
<varlistentry id="stats.arenas.i.bins.j.nonfull_slabs">
|
||||||
|
<term>
|
||||||
|
<mallctl>stats.arenas.<i>.bins.<j>.nonfull_slabs</mallctl>
|
||||||
|
(<type>size_t</type>)
|
||||||
|
<literal>r-</literal>
|
||||||
|
[<option>--enable-stats</option>]
|
||||||
|
</term>
|
||||||
|
<listitem><para>Current number of nonfull slabs.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry id="stats.arenas.i.bins.mutex">
|
<varlistentry id="stats.arenas.i.bins.mutex">
|
||||||
<term>
|
<term>
|
||||||
<mallctl>stats.arenas.<i>.bins.<j>.mutex.{counter}</mallctl>
|
<mallctl>stats.arenas.<i>.bins.<j>.mutex.{counter}</mallctl>
|
||||||
@ -2922,6 +3032,30 @@ struct extent_hooks_s {
|
|||||||
counters</link>.</para></listitem>
|
counters</link>.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="stats.arenas.i.extents.n">
|
||||||
|
<term>
|
||||||
|
<mallctl>stats.arenas.<i>.extents.<j>.n{extent_type}</mallctl>
|
||||||
|
(<type>size_t</type>)
|
||||||
|
<literal>r-</literal>
|
||||||
|
[<option>--enable-stats</option>]
|
||||||
|
</term>
|
||||||
|
<listitem><para> Number of extents of the given type in this arena in
|
||||||
|
the bucket corresponding to page size index <j>. The extent type
|
||||||
|
is one of dirty, muzzy, or retained.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="stats.arenas.i.extents.bytes">
|
||||||
|
<term>
|
||||||
|
<mallctl>stats.arenas.<i>.extents.<j>.{extent_type}_bytes</mallctl>
|
||||||
|
(<type>size_t</type>)
|
||||||
|
<literal>r-</literal>
|
||||||
|
[<option>--enable-stats</option>]
|
||||||
|
</term>
|
||||||
|
<listitem><para> Sum of the bytes managed by extents of the given type
|
||||||
|
in this arena in the bucket corresponding to page size index <j>.
|
||||||
|
The extent type is one of dirty, muzzy, or retained.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry id="stats.arenas.i.lextents.j.nmalloc">
|
<varlistentry id="stats.arenas.i.lextents.j.nmalloc">
|
||||||
<term>
|
<term>
|
||||||
<mallctl>stats.arenas.<i>.lextents.<j>.nmalloc</mallctl>
|
<mallctl>stats.arenas.<i>.lextents.<j>.nmalloc</mallctl>
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
#include "jemalloc/internal/bin.h"
|
#include "jemalloc/internal/bin.h"
|
||||||
#include "jemalloc/internal/extent_dss.h"
|
#include "jemalloc/internal/extent_dss.h"
|
||||||
|
#include "jemalloc/internal/hook.h"
|
||||||
#include "jemalloc/internal/pages.h"
|
#include "jemalloc/internal/pages.h"
|
||||||
#include "jemalloc/internal/size_classes.h"
|
|
||||||
#include "jemalloc/internal/stats.h"
|
#include "jemalloc/internal/stats.h"
|
||||||
|
|
||||||
extern ssize_t opt_dirty_decay_ms;
|
extern ssize_t opt_dirty_decay_ms;
|
||||||
@ -16,13 +16,17 @@ extern const char *percpu_arena_mode_names[];
|
|||||||
extern const uint64_t h_steps[SMOOTHSTEP_NSTEPS];
|
extern const uint64_t h_steps[SMOOTHSTEP_NSTEPS];
|
||||||
extern malloc_mutex_t arenas_lock;
|
extern malloc_mutex_t arenas_lock;
|
||||||
|
|
||||||
|
extern size_t opt_oversize_threshold;
|
||||||
|
extern size_t oversize_threshold;
|
||||||
|
|
||||||
void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena,
|
void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena,
|
||||||
unsigned *nthreads, const char **dss, ssize_t *dirty_decay_ms,
|
unsigned *nthreads, const char **dss, ssize_t *dirty_decay_ms,
|
||||||
ssize_t *muzzy_decay_ms, size_t *nactive, size_t *ndirty, size_t *nmuzzy);
|
ssize_t *muzzy_decay_ms, size_t *nactive, size_t *ndirty, size_t *nmuzzy);
|
||||||
void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
||||||
const char **dss, ssize_t *dirty_decay_ms, ssize_t *muzzy_decay_ms,
|
const char **dss, ssize_t *dirty_decay_ms, ssize_t *muzzy_decay_ms,
|
||||||
size_t *nactive, size_t *ndirty, size_t *nmuzzy, arena_stats_t *astats,
|
size_t *nactive, size_t *ndirty, size_t *nmuzzy, arena_stats_t *astats,
|
||||||
bin_stats_t *bstats, arena_stats_large_t *lstats);
|
bin_stats_t *bstats, arena_stats_large_t *lstats,
|
||||||
|
arena_stats_extents_t *estats);
|
||||||
void arena_extents_dirty_dalloc(tsdn_t *tsdn, arena_t *arena,
|
void arena_extents_dirty_dalloc(tsdn_t *tsdn, arena_t *arena,
|
||||||
extent_hooks_t **r_extent_hooks, extent_t *extent);
|
extent_hooks_t **r_extent_hooks, extent_t *extent);
|
||||||
#ifdef JEMALLOC_JET
|
#ifdef JEMALLOC_JET
|
||||||
@ -56,16 +60,17 @@ void *arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size,
|
|||||||
szind_t ind, bool zero);
|
szind_t ind, bool zero);
|
||||||
void *arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize,
|
void *arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize,
|
||||||
size_t alignment, bool zero, tcache_t *tcache);
|
size_t alignment, bool zero, tcache_t *tcache);
|
||||||
void arena_prof_promote(tsdn_t *tsdn, const void *ptr, size_t usize);
|
void arena_prof_promote(tsdn_t *tsdn, void *ptr, size_t usize);
|
||||||
void arena_dalloc_promoted(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
|
void arena_dalloc_promoted(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
|
||||||
bool slow_path);
|
bool slow_path);
|
||||||
void arena_dalloc_bin_junked_locked(tsdn_t *tsdn, arena_t *arena,
|
void arena_dalloc_bin_junked_locked(tsdn_t *tsdn, arena_t *arena, bin_t *bin,
|
||||||
extent_t *extent, void *ptr);
|
szind_t binind, extent_t *extent, void *ptr);
|
||||||
void arena_dalloc_small(tsdn_t *tsdn, void *ptr);
|
void arena_dalloc_small(tsdn_t *tsdn, void *ptr);
|
||||||
bool arena_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
|
bool arena_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
|
||||||
size_t extra, bool zero);
|
size_t extra, bool zero, size_t *newsize);
|
||||||
void *arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize,
|
void *arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize,
|
||||||
size_t size, size_t alignment, bool zero, tcache_t *tcache);
|
size_t size, size_t alignment, bool zero, tcache_t *tcache,
|
||||||
|
hook_ralloc_args_t *hook_args);
|
||||||
dss_prec_t arena_dss_prec_get(arena_t *arena);
|
dss_prec_t arena_dss_prec_get(arena_t *arena);
|
||||||
bool arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec);
|
bool arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec);
|
||||||
ssize_t arena_dirty_decay_ms_default_get(void);
|
ssize_t arena_dirty_decay_ms_default_get(void);
|
||||||
@ -79,7 +84,12 @@ void arena_nthreads_inc(arena_t *arena, bool internal);
|
|||||||
void arena_nthreads_dec(arena_t *arena, bool internal);
|
void arena_nthreads_dec(arena_t *arena, bool internal);
|
||||||
size_t arena_extent_sn_next(arena_t *arena);
|
size_t arena_extent_sn_next(arena_t *arena);
|
||||||
arena_t *arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks);
|
arena_t *arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks);
|
||||||
void arena_boot(void);
|
bool arena_init_huge(void);
|
||||||
|
bool arena_is_huge(unsigned arena_ind);
|
||||||
|
arena_t *arena_choose_huge(tsd_t *tsd);
|
||||||
|
bin_t *arena_bin_choose_lock(tsdn_t *tsdn, arena_t *arena, szind_t binind,
|
||||||
|
unsigned *binshard);
|
||||||
|
void arena_boot(sc_data_t *sc_data);
|
||||||
void arena_prefork0(tsdn_t *tsdn, arena_t *arena);
|
void arena_prefork0(tsdn_t *tsdn, arena_t *arena);
|
||||||
void arena_prefork1(tsdn_t *tsdn, arena_t *arena);
|
void arena_prefork1(tsdn_t *tsdn, arena_t *arena);
|
||||||
void arena_prefork2(tsdn_t *tsdn, arena_t *arena);
|
void arena_prefork2(tsdn_t *tsdn, arena_t *arena);
|
||||||
|
@ -4,10 +4,36 @@
|
|||||||
#include "jemalloc/internal/jemalloc_internal_types.h"
|
#include "jemalloc/internal/jemalloc_internal_types.h"
|
||||||
#include "jemalloc/internal/mutex.h"
|
#include "jemalloc/internal/mutex.h"
|
||||||
#include "jemalloc/internal/rtree.h"
|
#include "jemalloc/internal/rtree.h"
|
||||||
#include "jemalloc/internal/size_classes.h"
|
#include "jemalloc/internal/sc.h"
|
||||||
#include "jemalloc/internal/sz.h"
|
#include "jemalloc/internal/sz.h"
|
||||||
#include "jemalloc/internal/ticker.h"
|
#include "jemalloc/internal/ticker.h"
|
||||||
|
|
||||||
|
JEMALLOC_ALWAYS_INLINE bool
|
||||||
|
arena_has_default_hooks(arena_t *arena) {
|
||||||
|
return (extent_hooks_get(arena) == &extent_hooks_default);
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_ALWAYS_INLINE arena_t *
|
||||||
|
arena_choose_maybe_huge(tsd_t *tsd, arena_t *arena, size_t size) {
|
||||||
|
if (arena != NULL) {
|
||||||
|
return arena;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For huge allocations, use the dedicated huge arena if both are true:
|
||||||
|
* 1) is using auto arena selection (i.e. arena == NULL), and 2) the
|
||||||
|
* thread is not assigned to a manual arena.
|
||||||
|
*/
|
||||||
|
if (unlikely(size >= oversize_threshold)) {
|
||||||
|
arena_t *tsd_arena = tsd_arena_get(tsd);
|
||||||
|
if (tsd_arena == NULL || arena_is_auto(tsd_arena)) {
|
||||||
|
return arena_choose_huge(tsd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return arena_choose(tsd, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE prof_tctx_t *
|
JEMALLOC_ALWAYS_INLINE prof_tctx_t *
|
||||||
arena_prof_tctx_get(tsdn_t *tsdn, const void *ptr, alloc_ctx_t *alloc_ctx) {
|
arena_prof_tctx_get(tsdn_t *tsdn, const void *ptr, alloc_ctx_t *alloc_ctx) {
|
||||||
cassert(config_prof);
|
cassert(config_prof);
|
||||||
@ -28,7 +54,7 @@ arena_prof_tctx_get(tsdn_t *tsdn, const void *ptr, alloc_ctx_t *alloc_ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
arena_prof_tctx_set(tsdn_t *tsdn, const void *ptr, UNUSED size_t usize,
|
arena_prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize,
|
||||||
alloc_ctx_t *alloc_ctx, prof_tctx_t *tctx) {
|
alloc_ctx_t *alloc_ctx, prof_tctx_t *tctx) {
|
||||||
cassert(config_prof);
|
cassert(config_prof);
|
||||||
assert(ptr != NULL);
|
assert(ptr != NULL);
|
||||||
@ -47,7 +73,7 @@ arena_prof_tctx_set(tsdn_t *tsdn, const void *ptr, UNUSED size_t usize,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
arena_prof_tctx_reset(tsdn_t *tsdn, const void *ptr, UNUSED prof_tctx_t *tctx) {
|
arena_prof_tctx_reset(tsdn_t *tsdn, const void *ptr, prof_tctx_t *tctx) {
|
||||||
cassert(config_prof);
|
cassert(config_prof);
|
||||||
assert(ptr != NULL);
|
assert(ptr != NULL);
|
||||||
|
|
||||||
@ -57,6 +83,32 @@ arena_prof_tctx_reset(tsdn_t *tsdn, const void *ptr, UNUSED prof_tctx_t *tctx) {
|
|||||||
large_prof_tctx_reset(tsdn, extent);
|
large_prof_tctx_reset(tsdn, extent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JEMALLOC_ALWAYS_INLINE nstime_t
|
||||||
|
arena_prof_alloc_time_get(tsdn_t *tsdn, const void *ptr,
|
||||||
|
alloc_ctx_t *alloc_ctx) {
|
||||||
|
cassert(config_prof);
|
||||||
|
assert(ptr != NULL);
|
||||||
|
|
||||||
|
extent_t *extent = iealloc(tsdn, ptr);
|
||||||
|
/*
|
||||||
|
* Unlike arena_prof_prof_tctx_{get, set}, we only call this once we're
|
||||||
|
* sure we have a sampled allocation.
|
||||||
|
*/
|
||||||
|
assert(!extent_slab_get(extent));
|
||||||
|
return large_prof_alloc_time_get(extent);
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
|
arena_prof_alloc_time_set(tsdn_t *tsdn, const void *ptr, alloc_ctx_t *alloc_ctx,
|
||||||
|
nstime_t t) {
|
||||||
|
cassert(config_prof);
|
||||||
|
assert(ptr != NULL);
|
||||||
|
|
||||||
|
extent_t *extent = iealloc(tsdn, ptr);
|
||||||
|
assert(!extent_slab_get(extent));
|
||||||
|
large_prof_alloc_time_set(extent, t);
|
||||||
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks) {
|
arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks) {
|
||||||
tsd_t *tsd;
|
tsd_t *tsd;
|
||||||
@ -83,14 +135,33 @@ arena_decay_tick(tsdn_t *tsdn, arena_t *arena) {
|
|||||||
arena_decay_ticks(tsdn, arena, 1);
|
arena_decay_ticks(tsdn, arena, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Purge a single extent to retained / unmapped directly. */
|
||||||
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
|
arena_decay_extent(tsdn_t *tsdn,arena_t *arena, extent_hooks_t **r_extent_hooks,
|
||||||
|
extent_t *extent) {
|
||||||
|
size_t extent_size = extent_size_get(extent);
|
||||||
|
extent_dalloc_wrapper(tsdn, arena,
|
||||||
|
r_extent_hooks, extent);
|
||||||
|
if (config_stats) {
|
||||||
|
/* Update stats accordingly. */
|
||||||
|
arena_stats_lock(tsdn, &arena->stats);
|
||||||
|
arena_stats_add_u64(tsdn, &arena->stats,
|
||||||
|
&arena->decay_dirty.stats->nmadvise, 1);
|
||||||
|
arena_stats_add_u64(tsdn, &arena->stats,
|
||||||
|
&arena->decay_dirty.stats->purged, extent_size >> LG_PAGE);
|
||||||
|
arena_stats_sub_zu(tsdn, &arena->stats, &arena->stats.mapped,
|
||||||
|
extent_size);
|
||||||
|
arena_stats_unlock(tsdn, &arena->stats);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void *
|
JEMALLOC_ALWAYS_INLINE void *
|
||||||
arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero,
|
arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero,
|
||||||
tcache_t *tcache, bool slow_path) {
|
tcache_t *tcache, bool slow_path) {
|
||||||
assert(!tsdn_null(tsdn) || tcache == NULL);
|
assert(!tsdn_null(tsdn) || tcache == NULL);
|
||||||
assert(size != 0);
|
|
||||||
|
|
||||||
if (likely(tcache != NULL)) {
|
if (likely(tcache != NULL)) {
|
||||||
if (likely(size <= SMALL_MAXCLASS)) {
|
if (likely(size <= SC_SMALL_MAXCLASS)) {
|
||||||
return tcache_alloc_small(tsdn_tsd(tsdn), arena,
|
return tcache_alloc_small(tsdn_tsd(tsdn), arena,
|
||||||
tcache, size, ind, zero, slow_path);
|
tcache, size, ind, zero, slow_path);
|
||||||
}
|
}
|
||||||
@ -119,7 +190,7 @@ arena_salloc(tsdn_t *tsdn, const void *ptr) {
|
|||||||
|
|
||||||
szind_t szind = rtree_szind_read(tsdn, &extents_rtree, rtree_ctx,
|
szind_t szind = rtree_szind_read(tsdn, &extents_rtree, rtree_ctx,
|
||||||
(uintptr_t)ptr, true);
|
(uintptr_t)ptr, true);
|
||||||
assert(szind != NSIZES);
|
assert(szind != SC_NSIZES);
|
||||||
|
|
||||||
return sz_index2size(szind);
|
return sz_index2size(szind);
|
||||||
}
|
}
|
||||||
@ -152,11 +223,21 @@ arena_vsalloc(tsdn_t *tsdn, const void *ptr) {
|
|||||||
/* Only slab members should be looked up via interior pointers. */
|
/* Only slab members should be looked up via interior pointers. */
|
||||||
assert(extent_addr_get(extent) == ptr || extent_slab_get(extent));
|
assert(extent_addr_get(extent) == ptr || extent_slab_get(extent));
|
||||||
|
|
||||||
assert(szind != NSIZES);
|
assert(szind != SC_NSIZES);
|
||||||
|
|
||||||
return sz_index2size(szind);
|
return sz_index2size(szind);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
arena_dalloc_large_no_tcache(tsdn_t *tsdn, void *ptr, szind_t szind) {
|
||||||
|
if (config_prof && unlikely(szind < SC_NBINS)) {
|
||||||
|
arena_dalloc_promoted(tsdn, ptr, NULL, true);
|
||||||
|
} else {
|
||||||
|
extent_t *extent = iealloc(tsdn, ptr);
|
||||||
|
large_dalloc(tsdn, extent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
arena_dalloc_no_tcache(tsdn_t *tsdn, void *ptr) {
|
arena_dalloc_no_tcache(tsdn_t *tsdn, void *ptr) {
|
||||||
assert(ptr != NULL);
|
assert(ptr != NULL);
|
||||||
@ -173,13 +254,28 @@ arena_dalloc_no_tcache(tsdn_t *tsdn, void *ptr) {
|
|||||||
extent_t *extent = rtree_extent_read(tsdn, &extents_rtree,
|
extent_t *extent = rtree_extent_read(tsdn, &extents_rtree,
|
||||||
rtree_ctx, (uintptr_t)ptr, true);
|
rtree_ctx, (uintptr_t)ptr, true);
|
||||||
assert(szind == extent_szind_get(extent));
|
assert(szind == extent_szind_get(extent));
|
||||||
assert(szind < NSIZES);
|
assert(szind < SC_NSIZES);
|
||||||
assert(slab == extent_slab_get(extent));
|
assert(slab == extent_slab_get(extent));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (likely(slab)) {
|
if (likely(slab)) {
|
||||||
/* Small allocation. */
|
/* Small allocation. */
|
||||||
arena_dalloc_small(tsdn, ptr);
|
arena_dalloc_small(tsdn, ptr);
|
||||||
|
} else {
|
||||||
|
arena_dalloc_large_no_tcache(tsdn, ptr, szind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
|
arena_dalloc_large(tsdn_t *tsdn, void *ptr, tcache_t *tcache, szind_t szind,
|
||||||
|
bool slow_path) {
|
||||||
|
if (szind < nhbins) {
|
||||||
|
if (config_prof && unlikely(szind < SC_NBINS)) {
|
||||||
|
arena_dalloc_promoted(tsdn, ptr, tcache, slow_path);
|
||||||
|
} else {
|
||||||
|
tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, szind,
|
||||||
|
slow_path);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
extent_t *extent = iealloc(tsdn, ptr);
|
extent_t *extent = iealloc(tsdn, ptr);
|
||||||
large_dalloc(tsdn, extent);
|
large_dalloc(tsdn, extent);
|
||||||
@ -203,7 +299,7 @@ arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
|
|||||||
if (alloc_ctx != NULL) {
|
if (alloc_ctx != NULL) {
|
||||||
szind = alloc_ctx->szind;
|
szind = alloc_ctx->szind;
|
||||||
slab = alloc_ctx->slab;
|
slab = alloc_ctx->slab;
|
||||||
assert(szind != NSIZES);
|
assert(szind != SC_NSIZES);
|
||||||
} else {
|
} else {
|
||||||
rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn));
|
rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn));
|
||||||
rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx,
|
rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx,
|
||||||
@ -215,7 +311,7 @@ arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
|
|||||||
extent_t *extent = rtree_extent_read(tsdn, &extents_rtree,
|
extent_t *extent = rtree_extent_read(tsdn, &extents_rtree,
|
||||||
rtree_ctx, (uintptr_t)ptr, true);
|
rtree_ctx, (uintptr_t)ptr, true);
|
||||||
assert(szind == extent_szind_get(extent));
|
assert(szind == extent_szind_get(extent));
|
||||||
assert(szind < NSIZES);
|
assert(szind < SC_NSIZES);
|
||||||
assert(slab == extent_slab_get(extent));
|
assert(slab == extent_slab_get(extent));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,25 +320,14 @@ arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
|
|||||||
tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind,
|
tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind,
|
||||||
slow_path);
|
slow_path);
|
||||||
} else {
|
} else {
|
||||||
if (szind < nhbins) {
|
arena_dalloc_large(tsdn, ptr, tcache, szind, slow_path);
|
||||||
if (config_prof && unlikely(szind < NBINS)) {
|
|
||||||
arena_dalloc_promoted(tsdn, ptr, tcache,
|
|
||||||
slow_path);
|
|
||||||
} else {
|
|
||||||
tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr,
|
|
||||||
szind, slow_path);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
extent_t *extent = iealloc(tsdn, ptr);
|
|
||||||
large_dalloc(tsdn, extent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) {
|
arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) {
|
||||||
assert(ptr != NULL);
|
assert(ptr != NULL);
|
||||||
assert(size <= LARGE_MAXCLASS);
|
assert(size <= SC_LARGE_MAXCLASS);
|
||||||
|
|
||||||
szind_t szind;
|
szind_t szind;
|
||||||
bool slab;
|
bool slab;
|
||||||
@ -252,7 +337,7 @@ arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) {
|
|||||||
* object, so base szind and slab on the given size.
|
* object, so base szind and slab on the given size.
|
||||||
*/
|
*/
|
||||||
szind = sz_size2index(size);
|
szind = sz_size2index(size);
|
||||||
slab = (szind < NBINS);
|
slab = (szind < SC_NBINS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((config_prof && opt_prof) || config_debug) {
|
if ((config_prof && opt_prof) || config_debug) {
|
||||||
@ -264,7 +349,7 @@ arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) {
|
|||||||
(uintptr_t)ptr, true, &szind, &slab);
|
(uintptr_t)ptr, true, &szind, &slab);
|
||||||
|
|
||||||
assert(szind == sz_size2index(size));
|
assert(szind == sz_size2index(size));
|
||||||
assert((config_prof && opt_prof) || slab == (szind < NBINS));
|
assert((config_prof && opt_prof) || slab == (szind < SC_NBINS));
|
||||||
|
|
||||||
if (config_debug) {
|
if (config_debug) {
|
||||||
extent_t *extent = rtree_extent_read(tsdn,
|
extent_t *extent = rtree_extent_read(tsdn,
|
||||||
@ -278,8 +363,7 @@ arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) {
|
|||||||
/* Small allocation. */
|
/* Small allocation. */
|
||||||
arena_dalloc_small(tsdn, ptr);
|
arena_dalloc_small(tsdn, ptr);
|
||||||
} else {
|
} else {
|
||||||
extent_t *extent = iealloc(tsdn, ptr);
|
arena_dalloc_large_no_tcache(tsdn, ptr, szind);
|
||||||
large_dalloc(tsdn, extent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,7 +372,7 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
|
|||||||
alloc_ctx_t *alloc_ctx, bool slow_path) {
|
alloc_ctx_t *alloc_ctx, bool slow_path) {
|
||||||
assert(!tsdn_null(tsdn) || tcache == NULL);
|
assert(!tsdn_null(tsdn) || tcache == NULL);
|
||||||
assert(ptr != NULL);
|
assert(ptr != NULL);
|
||||||
assert(size <= LARGE_MAXCLASS);
|
assert(size <= SC_LARGE_MAXCLASS);
|
||||||
|
|
||||||
if (unlikely(tcache == NULL)) {
|
if (unlikely(tcache == NULL)) {
|
||||||
arena_sdalloc_no_tcache(tsdn, ptr, size);
|
arena_sdalloc_no_tcache(tsdn, ptr, size);
|
||||||
@ -297,7 +381,7 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
|
|||||||
|
|
||||||
szind_t szind;
|
szind_t szind;
|
||||||
bool slab;
|
bool slab;
|
||||||
UNUSED alloc_ctx_t local_ctx;
|
alloc_ctx_t local_ctx;
|
||||||
if (config_prof && opt_prof) {
|
if (config_prof && opt_prof) {
|
||||||
if (alloc_ctx == NULL) {
|
if (alloc_ctx == NULL) {
|
||||||
/* Uncommon case and should be a static check. */
|
/* Uncommon case and should be a static check. */
|
||||||
@ -318,7 +402,7 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
|
|||||||
* object, so base szind and slab on the given size.
|
* object, so base szind and slab on the given size.
|
||||||
*/
|
*/
|
||||||
szind = sz_size2index(size);
|
szind = sz_size2index(size);
|
||||||
slab = (szind < NBINS);
|
slab = (szind < SC_NBINS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config_debug) {
|
if (config_debug) {
|
||||||
@ -336,18 +420,7 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
|
|||||||
tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind,
|
tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind,
|
||||||
slow_path);
|
slow_path);
|
||||||
} else {
|
} else {
|
||||||
if (szind < nhbins) {
|
arena_dalloc_large(tsdn, ptr, tcache, szind, slow_path);
|
||||||
if (config_prof && unlikely(szind < NBINS)) {
|
|
||||||
arena_dalloc_promoted(tsdn, ptr, tcache,
|
|
||||||
slow_path);
|
|
||||||
} else {
|
|
||||||
tcache_dalloc_large(tsdn_tsd(tsdn),
|
|
||||||
tcache, ptr, szind, slow_path);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
extent_t *extent = iealloc(tsdn, ptr);
|
|
||||||
large_dalloc(tsdn, extent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,9 @@
|
|||||||
#include "jemalloc/internal/atomic.h"
|
#include "jemalloc/internal/atomic.h"
|
||||||
#include "jemalloc/internal/mutex.h"
|
#include "jemalloc/internal/mutex.h"
|
||||||
#include "jemalloc/internal/mutex_prof.h"
|
#include "jemalloc/internal/mutex_prof.h"
|
||||||
#include "jemalloc/internal/size_classes.h"
|
#include "jemalloc/internal/sc.h"
|
||||||
|
|
||||||
|
JEMALLOC_DIAGNOSTIC_DISABLE_SPURIOUS
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In those architectures that support 64-bit atomics, we use atomic updates for
|
* In those architectures that support 64-bit atomics, we use atomic updates for
|
||||||
@ -33,6 +35,13 @@ struct arena_stats_large_s {
|
|||||||
* periodically merges into this counter.
|
* periodically merges into this counter.
|
||||||
*/
|
*/
|
||||||
arena_stats_u64_t nrequests; /* Partially derived. */
|
arena_stats_u64_t nrequests; /* Partially derived. */
|
||||||
|
/*
|
||||||
|
* Number of tcache fills / flushes for large (similarly, periodically
|
||||||
|
* merged). Note that there is no large tcache batch-fill currently
|
||||||
|
* (i.e. only fill 1 at a time); however flush may be batched.
|
||||||
|
*/
|
||||||
|
arena_stats_u64_t nfills; /* Partially derived. */
|
||||||
|
arena_stats_u64_t nflushes; /* Partially derived. */
|
||||||
|
|
||||||
/* Current number of allocations of this size class. */
|
/* Current number of allocations of this size class. */
|
||||||
size_t curlextents; /* Derived. */
|
size_t curlextents; /* Derived. */
|
||||||
@ -48,6 +57,22 @@ struct arena_stats_decay_s {
|
|||||||
arena_stats_u64_t purged;
|
arena_stats_u64_t purged;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct arena_stats_extents_s arena_stats_extents_t;
|
||||||
|
struct arena_stats_extents_s {
|
||||||
|
/*
|
||||||
|
* Stats for a given index in the range [0, SC_NPSIZES] in an extents_t.
|
||||||
|
* We track both bytes and # of extents: two extents in the same bucket
|
||||||
|
* may have different sizes if adjacent size classes differ by more than
|
||||||
|
* a page, so bytes cannot always be derived from # of extents.
|
||||||
|
*/
|
||||||
|
atomic_zu_t ndirty;
|
||||||
|
atomic_zu_t dirty_bytes;
|
||||||
|
atomic_zu_t nmuzzy;
|
||||||
|
atomic_zu_t muzzy_bytes;
|
||||||
|
atomic_zu_t nretained;
|
||||||
|
atomic_zu_t retained_bytes;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Arena stats. Note that fields marked "derived" are not directly maintained
|
* Arena stats. Note that fields marked "derived" are not directly maintained
|
||||||
* within the arena code; rather their values are derived during stats merge
|
* within the arena code; rather their values are derived during stats merge
|
||||||
@ -69,6 +94,9 @@ struct arena_stats_s {
|
|||||||
*/
|
*/
|
||||||
atomic_zu_t retained; /* Derived. */
|
atomic_zu_t retained; /* Derived. */
|
||||||
|
|
||||||
|
/* Number of extent_t structs allocated by base, but not being used. */
|
||||||
|
atomic_zu_t extent_avail;
|
||||||
|
|
||||||
arena_stats_decay_t decay_dirty;
|
arena_stats_decay_t decay_dirty;
|
||||||
arena_stats_decay_t decay_muzzy;
|
arena_stats_decay_t decay_muzzy;
|
||||||
|
|
||||||
@ -80,22 +108,27 @@ struct arena_stats_s {
|
|||||||
atomic_zu_t allocated_large; /* Derived. */
|
atomic_zu_t allocated_large; /* Derived. */
|
||||||
arena_stats_u64_t nmalloc_large; /* Derived. */
|
arena_stats_u64_t nmalloc_large; /* Derived. */
|
||||||
arena_stats_u64_t ndalloc_large; /* Derived. */
|
arena_stats_u64_t ndalloc_large; /* Derived. */
|
||||||
|
arena_stats_u64_t nfills_large; /* Derived. */
|
||||||
|
arena_stats_u64_t nflushes_large; /* Derived. */
|
||||||
arena_stats_u64_t nrequests_large; /* Derived. */
|
arena_stats_u64_t nrequests_large; /* Derived. */
|
||||||
|
|
||||||
|
/* VM space had to be leaked (undocumented). Normally 0. */
|
||||||
|
atomic_zu_t abandoned_vm;
|
||||||
|
|
||||||
/* Number of bytes cached in tcache associated with this arena. */
|
/* Number of bytes cached in tcache associated with this arena. */
|
||||||
atomic_zu_t tcache_bytes; /* Derived. */
|
atomic_zu_t tcache_bytes; /* Derived. */
|
||||||
|
|
||||||
mutex_prof_data_t mutex_prof_data[mutex_prof_num_arena_mutexes];
|
mutex_prof_data_t mutex_prof_data[mutex_prof_num_arena_mutexes];
|
||||||
|
|
||||||
/* One element for each large size class. */
|
/* One element for each large size class. */
|
||||||
arena_stats_large_t lstats[NSIZES - NBINS];
|
arena_stats_large_t lstats[SC_NSIZES - SC_NBINS];
|
||||||
|
|
||||||
/* Arena uptime. */
|
/* Arena uptime. */
|
||||||
nstime_t uptime;
|
nstime_t uptime;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
arena_stats_init(UNUSED tsdn_t *tsdn, arena_stats_t *arena_stats) {
|
arena_stats_init(tsdn_t *tsdn, arena_stats_t *arena_stats) {
|
||||||
if (config_debug) {
|
if (config_debug) {
|
||||||
for (size_t i = 0; i < sizeof(arena_stats_t); i++) {
|
for (size_t i = 0; i < sizeof(arena_stats_t); i++) {
|
||||||
assert(((char *)arena_stats)[i] == 0);
|
assert(((char *)arena_stats)[i] == 0);
|
||||||
@ -147,11 +180,11 @@ arena_stats_add_u64(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
UNUSED static inline void
|
static inline void
|
||||||
arena_stats_sub_u64(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
arena_stats_sub_u64(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
||||||
arena_stats_u64_t *p, uint64_t x) {
|
arena_stats_u64_t *p, uint64_t x) {
|
||||||
#ifdef JEMALLOC_ATOMIC_U64
|
#ifdef JEMALLOC_ATOMIC_U64
|
||||||
UNUSED uint64_t r = atomic_fetch_sub_u64(p, x, ATOMIC_RELAXED);
|
uint64_t r = atomic_fetch_sub_u64(p, x, ATOMIC_RELAXED);
|
||||||
assert(r - x <= r);
|
assert(r - x <= r);
|
||||||
#else
|
#else
|
||||||
malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
|
malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
|
||||||
@ -176,7 +209,8 @@ arena_stats_accum_u64(arena_stats_u64_t *dst, uint64_t src) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline size_t
|
static inline size_t
|
||||||
arena_stats_read_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, atomic_zu_t *p) {
|
arena_stats_read_zu(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
||||||
|
atomic_zu_t *p) {
|
||||||
#ifdef JEMALLOC_ATOMIC_U64
|
#ifdef JEMALLOC_ATOMIC_U64
|
||||||
return atomic_load_zu(p, ATOMIC_RELAXED);
|
return atomic_load_zu(p, ATOMIC_RELAXED);
|
||||||
#else
|
#else
|
||||||
@ -186,8 +220,8 @@ arena_stats_read_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, atomic_zu_t *p) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
arena_stats_add_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, atomic_zu_t *p,
|
arena_stats_add_zu(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
||||||
size_t x) {
|
atomic_zu_t *p, size_t x) {
|
||||||
#ifdef JEMALLOC_ATOMIC_U64
|
#ifdef JEMALLOC_ATOMIC_U64
|
||||||
atomic_fetch_add_zu(p, x, ATOMIC_RELAXED);
|
atomic_fetch_add_zu(p, x, ATOMIC_RELAXED);
|
||||||
#else
|
#else
|
||||||
@ -198,10 +232,10 @@ arena_stats_add_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, atomic_zu_t *p,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
arena_stats_sub_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, atomic_zu_t *p,
|
arena_stats_sub_zu(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
||||||
size_t x) {
|
atomic_zu_t *p, size_t x) {
|
||||||
#ifdef JEMALLOC_ATOMIC_U64
|
#ifdef JEMALLOC_ATOMIC_U64
|
||||||
UNUSED size_t r = atomic_fetch_sub_zu(p, x, ATOMIC_RELAXED);
|
size_t r = atomic_fetch_sub_zu(p, x, ATOMIC_RELAXED);
|
||||||
assert(r - x <= r);
|
assert(r - x <= r);
|
||||||
#else
|
#else
|
||||||
malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
|
malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
|
||||||
@ -218,11 +252,12 @@ arena_stats_accum_zu(atomic_zu_t *dst, size_t src) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
arena_stats_large_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
arena_stats_large_flush_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
||||||
szind_t szind, uint64_t nrequests) {
|
szind_t szind, uint64_t nrequests) {
|
||||||
arena_stats_lock(tsdn, arena_stats);
|
arena_stats_lock(tsdn, arena_stats);
|
||||||
arena_stats_add_u64(tsdn, arena_stats, &arena_stats->lstats[szind -
|
arena_stats_large_t *lstats = &arena_stats->lstats[szind - SC_NBINS];
|
||||||
NBINS].nrequests, nrequests);
|
arena_stats_add_u64(tsdn, arena_stats, &lstats->nrequests, nrequests);
|
||||||
|
arena_stats_add_u64(tsdn, arena_stats, &lstats->nflushes, 1);
|
||||||
arena_stats_unlock(tsdn, arena_stats);
|
arena_stats_unlock(tsdn, arena_stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,5 +268,4 @@ arena_stats_mapped_add(tsdn_t *tsdn, arena_stats_t *arena_stats, size_t size) {
|
|||||||
arena_stats_unlock(tsdn, arena_stats);
|
arena_stats_unlock(tsdn, arena_stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_ARENA_STATS_H */
|
#endif /* JEMALLOC_INTERNAL_ARENA_STATS_H */
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
#include "jemalloc/internal/mutex.h"
|
#include "jemalloc/internal/mutex.h"
|
||||||
#include "jemalloc/internal/nstime.h"
|
#include "jemalloc/internal/nstime.h"
|
||||||
#include "jemalloc/internal/ql.h"
|
#include "jemalloc/internal/ql.h"
|
||||||
#include "jemalloc/internal/size_classes.h"
|
#include "jemalloc/internal/sc.h"
|
||||||
#include "jemalloc/internal/smoothstep.h"
|
#include "jemalloc/internal/smoothstep.h"
|
||||||
#include "jemalloc/internal/ticker.h"
|
#include "jemalloc/internal/ticker.h"
|
||||||
|
|
||||||
@ -90,6 +90,9 @@ struct arena_s {
|
|||||||
*/
|
*/
|
||||||
atomic_u_t nthreads[2];
|
atomic_u_t nthreads[2];
|
||||||
|
|
||||||
|
/* Next bin shard for binding new threads. Synchronization: atomic. */
|
||||||
|
atomic_u_t binshard_next;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When percpu_arena is enabled, to amortize the cost of reading /
|
* When percpu_arena is enabled, to amortize the cost of reading /
|
||||||
* updating the current CPU id, track the most recent thread accessing
|
* updating the current CPU id, track the most recent thread accessing
|
||||||
@ -113,7 +116,6 @@ struct arena_s {
|
|||||||
|
|
||||||
/* Synchronization: internal. */
|
/* Synchronization: internal. */
|
||||||
prof_accum_t prof_accum;
|
prof_accum_t prof_accum;
|
||||||
uint64_t prof_accumbytes;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PRNG state for cache index randomization of large allocation base
|
* PRNG state for cache index randomization of large allocation base
|
||||||
@ -196,6 +198,7 @@ struct arena_s {
|
|||||||
* Synchronization: extent_avail_mtx.
|
* Synchronization: extent_avail_mtx.
|
||||||
*/
|
*/
|
||||||
extent_tree_t extent_avail;
|
extent_tree_t extent_avail;
|
||||||
|
atomic_zu_t extent_avail_cnt;
|
||||||
malloc_mutex_t extent_avail_mtx;
|
malloc_mutex_t extent_avail_mtx;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -203,7 +206,7 @@ struct arena_s {
|
|||||||
*
|
*
|
||||||
* Synchronization: internal.
|
* Synchronization: internal.
|
||||||
*/
|
*/
|
||||||
bin_t bins[NBINS];
|
bins_t bins[SC_NBINS];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Base allocator, from which arena metadata are allocated.
|
* Base allocator, from which arena metadata are allocated.
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
#ifndef JEMALLOC_INTERNAL_ARENA_TYPES_H
|
#ifndef JEMALLOC_INTERNAL_ARENA_TYPES_H
|
||||||
#define JEMALLOC_INTERNAL_ARENA_TYPES_H
|
#define JEMALLOC_INTERNAL_ARENA_TYPES_H
|
||||||
|
|
||||||
|
#include "jemalloc/internal/sc.h"
|
||||||
|
|
||||||
/* Maximum number of regions in one slab. */
|
/* Maximum number of regions in one slab. */
|
||||||
#define LG_SLAB_MAXREGS (LG_PAGE - LG_TINY_MIN)
|
#define LG_SLAB_MAXREGS (LG_PAGE - SC_LG_TINY_MIN)
|
||||||
#define SLAB_MAXREGS (1U << LG_SLAB_MAXREGS)
|
#define SLAB_MAXREGS (1U << LG_SLAB_MAXREGS)
|
||||||
|
|
||||||
/* Default decay times in milliseconds. */
|
/* Default decay times in milliseconds. */
|
||||||
#define DIRTY_DECAY_MS_DEFAULT ZD(10 * 1000)
|
#define DIRTY_DECAY_MS_DEFAULT ZD(10 * 1000)
|
||||||
#define MUZZY_DECAY_MS_DEFAULT ZD(10 * 1000)
|
#define MUZZY_DECAY_MS_DEFAULT (0)
|
||||||
/* Number of event ticks between time checks. */
|
/* Number of event ticks between time checks. */
|
||||||
#define DECAY_NTICKS_PER_UPDATE 1000
|
#define DECAY_NTICKS_PER_UPDATE 1000
|
||||||
|
|
||||||
@ -40,4 +42,10 @@ typedef enum {
|
|||||||
#define PERCPU_ARENA_ENABLED(m) ((m) >= percpu_arena_mode_enabled_base)
|
#define PERCPU_ARENA_ENABLED(m) ((m) >= percpu_arena_mode_enabled_base)
|
||||||
#define PERCPU_ARENA_DEFAULT percpu_arena_disabled
|
#define PERCPU_ARENA_DEFAULT percpu_arena_disabled
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When allocation_size >= oversize_threshold, use the dedicated huge arena
|
||||||
|
* (unless have explicitly spicified arena index). 0 disables the feature.
|
||||||
|
*/
|
||||||
|
#define OVERSIZE_THRESHOLD_DEFAULT (8 << 20)
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_ARENA_TYPES_H */
|
#endif /* JEMALLOC_INTERNAL_ARENA_TYPES_H */
|
||||||
|
11
deps/jemalloc/include/jemalloc/internal/atomic.h
vendored
11
deps/jemalloc/include/jemalloc/internal/atomic.h
vendored
@ -1,12 +1,19 @@
|
|||||||
#ifndef JEMALLOC_INTERNAL_ATOMIC_H
|
#ifndef JEMALLOC_INTERNAL_ATOMIC_H
|
||||||
#define JEMALLOC_INTERNAL_ATOMIC_H
|
#define JEMALLOC_INTERNAL_ATOMIC_H
|
||||||
|
|
||||||
#define ATOMIC_INLINE static inline
|
#define ATOMIC_INLINE JEMALLOC_ALWAYS_INLINE
|
||||||
|
|
||||||
|
#define JEMALLOC_U8_ATOMICS
|
||||||
#if defined(JEMALLOC_GCC_ATOMIC_ATOMICS)
|
#if defined(JEMALLOC_GCC_ATOMIC_ATOMICS)
|
||||||
# include "jemalloc/internal/atomic_gcc_atomic.h"
|
# include "jemalloc/internal/atomic_gcc_atomic.h"
|
||||||
|
# if !defined(JEMALLOC_GCC_U8_ATOMIC_ATOMICS)
|
||||||
|
# undef JEMALLOC_U8_ATOMICS
|
||||||
|
# endif
|
||||||
#elif defined(JEMALLOC_GCC_SYNC_ATOMICS)
|
#elif defined(JEMALLOC_GCC_SYNC_ATOMICS)
|
||||||
# include "jemalloc/internal/atomic_gcc_sync.h"
|
# include "jemalloc/internal/atomic_gcc_sync.h"
|
||||||
|
# if !defined(JEMALLOC_GCC_U8_SYNC_ATOMICS)
|
||||||
|
# undef JEMALLOC_U8_ATOMICS
|
||||||
|
# endif
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
# include "jemalloc/internal/atomic_msvc.h"
|
# include "jemalloc/internal/atomic_msvc.h"
|
||||||
#elif defined(JEMALLOC_C11_ATOMICS)
|
#elif defined(JEMALLOC_C11_ATOMICS)
|
||||||
@ -66,6 +73,8 @@ JEMALLOC_GENERATE_INT_ATOMICS(size_t, zu, LG_SIZEOF_PTR)
|
|||||||
|
|
||||||
JEMALLOC_GENERATE_INT_ATOMICS(ssize_t, zd, LG_SIZEOF_PTR)
|
JEMALLOC_GENERATE_INT_ATOMICS(ssize_t, zd, LG_SIZEOF_PTR)
|
||||||
|
|
||||||
|
JEMALLOC_GENERATE_INT_ATOMICS(uint8_t, u8, 0)
|
||||||
|
|
||||||
JEMALLOC_GENERATE_INT_ATOMICS(uint32_t, u32, 2)
|
JEMALLOC_GENERATE_INT_ATOMICS(uint32_t, u32, 2)
|
||||||
|
|
||||||
#ifdef JEMALLOC_ATOMIC_U64
|
#ifdef JEMALLOC_ATOMIC_U64
|
||||||
|
@ -67,7 +67,8 @@ atomic_exchange_##short_type(atomic_##short_type##_t *a, type val, \
|
|||||||
\
|
\
|
||||||
ATOMIC_INLINE bool \
|
ATOMIC_INLINE bool \
|
||||||
atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \
|
atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \
|
||||||
type *expected, type desired, atomic_memory_order_t success_mo, \
|
UNUSED type *expected, type desired, \
|
||||||
|
atomic_memory_order_t success_mo, \
|
||||||
atomic_memory_order_t failure_mo) { \
|
atomic_memory_order_t failure_mo) { \
|
||||||
return __atomic_compare_exchange(&a->repr, expected, &desired, \
|
return __atomic_compare_exchange(&a->repr, expected, &desired, \
|
||||||
true, atomic_enum_to_builtin(success_mo), \
|
true, atomic_enum_to_builtin(success_mo), \
|
||||||
@ -76,7 +77,8 @@ atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \
|
|||||||
\
|
\
|
||||||
ATOMIC_INLINE bool \
|
ATOMIC_INLINE bool \
|
||||||
atomic_compare_exchange_strong_##short_type(atomic_##short_type##_t *a, \
|
atomic_compare_exchange_strong_##short_type(atomic_##short_type##_t *a, \
|
||||||
type *expected, type desired, atomic_memory_order_t success_mo, \
|
UNUSED type *expected, type desired, \
|
||||||
|
atomic_memory_order_t success_mo, \
|
||||||
atomic_memory_order_t failure_mo) { \
|
atomic_memory_order_t failure_mo) { \
|
||||||
return __atomic_compare_exchange(&a->repr, expected, &desired, \
|
return __atomic_compare_exchange(&a->repr, expected, &desired, \
|
||||||
false, \
|
false, \
|
||||||
|
@ -27,8 +27,10 @@ atomic_fence(atomic_memory_order_t mo) {
|
|||||||
asm volatile("" ::: "memory");
|
asm volatile("" ::: "memory");
|
||||||
# if defined(__i386__) || defined(__x86_64__)
|
# if defined(__i386__) || defined(__x86_64__)
|
||||||
/* This is implicit on x86. */
|
/* This is implicit on x86. */
|
||||||
# elif defined(__ppc__)
|
# elif defined(__ppc64__)
|
||||||
asm volatile("lwsync");
|
asm volatile("lwsync");
|
||||||
|
# elif defined(__ppc__)
|
||||||
|
asm volatile("sync");
|
||||||
# elif defined(__sparc__) && defined(__arch64__)
|
# elif defined(__sparc__) && defined(__arch64__)
|
||||||
if (mo == atomic_memory_order_acquire) {
|
if (mo == atomic_memory_order_acquire) {
|
||||||
asm volatile("membar #LoadLoad | #LoadStore");
|
asm volatile("membar #LoadLoad | #LoadStore");
|
||||||
@ -129,7 +131,8 @@ atomic_exchange_##short_type(atomic_##short_type##_t *a, type val, \
|
|||||||
\
|
\
|
||||||
ATOMIC_INLINE bool \
|
ATOMIC_INLINE bool \
|
||||||
atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \
|
atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \
|
||||||
type *expected, type desired, atomic_memory_order_t success_mo, \
|
type *expected, type desired, \
|
||||||
|
atomic_memory_order_t success_mo, \
|
||||||
atomic_memory_order_t failure_mo) { \
|
atomic_memory_order_t failure_mo) { \
|
||||||
type prev = __sync_val_compare_and_swap(&a->repr, *expected, \
|
type prev = __sync_val_compare_and_swap(&a->repr, *expected, \
|
||||||
desired); \
|
desired); \
|
||||||
@ -142,7 +145,8 @@ atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \
|
|||||||
} \
|
} \
|
||||||
ATOMIC_INLINE bool \
|
ATOMIC_INLINE bool \
|
||||||
atomic_compare_exchange_strong_##short_type(atomic_##short_type##_t *a, \
|
atomic_compare_exchange_strong_##short_type(atomic_##short_type##_t *a, \
|
||||||
type *expected, type desired, atomic_memory_order_t success_mo, \
|
type *expected, type desired, \
|
||||||
|
atomic_memory_order_t success_mo, \
|
||||||
atomic_memory_order_t failure_mo) { \
|
atomic_memory_order_t failure_mo) { \
|
||||||
type prev = __sync_val_compare_and_swap(&a->repr, *expected, \
|
type prev = __sync_val_compare_and_swap(&a->repr, *expected, \
|
||||||
desired); \
|
desired); \
|
||||||
|
@ -8,7 +8,6 @@ extern atomic_b_t background_thread_enabled_state;
|
|||||||
extern size_t n_background_threads;
|
extern size_t n_background_threads;
|
||||||
extern size_t max_background_threads;
|
extern size_t max_background_threads;
|
||||||
extern background_thread_info_t *background_thread_info;
|
extern background_thread_info_t *background_thread_info;
|
||||||
extern bool can_enable_background_thread;
|
|
||||||
|
|
||||||
bool background_thread_create(tsd_t *tsd, unsigned arena_ind);
|
bool background_thread_create(tsd_t *tsd, unsigned arena_ind);
|
||||||
bool background_threads_enable(tsd_t *tsd);
|
bool background_threads_enable(tsd_t *tsd);
|
||||||
|
@ -15,7 +15,12 @@ background_thread_enabled_set(tsdn_t *tsdn, bool state) {
|
|||||||
JEMALLOC_ALWAYS_INLINE background_thread_info_t *
|
JEMALLOC_ALWAYS_INLINE background_thread_info_t *
|
||||||
arena_background_thread_info_get(arena_t *arena) {
|
arena_background_thread_info_get(arena_t *arena) {
|
||||||
unsigned arena_ind = arena_ind_get(arena);
|
unsigned arena_ind = arena_ind_get(arena);
|
||||||
return &background_thread_info[arena_ind % ncpus];
|
return &background_thread_info[arena_ind % max_background_threads];
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_ALWAYS_INLINE background_thread_info_t *
|
||||||
|
background_thread_info_get(size_t ind) {
|
||||||
|
return &background_thread_info[ind % max_background_threads];
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE uint64_t
|
JEMALLOC_ALWAYS_INLINE uint64_t
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#define BACKGROUND_THREAD_INDEFINITE_SLEEP UINT64_MAX
|
#define BACKGROUND_THREAD_INDEFINITE_SLEEP UINT64_MAX
|
||||||
#define MAX_BACKGROUND_THREAD_LIMIT MALLOCX_ARENA_LIMIT
|
#define MAX_BACKGROUND_THREAD_LIMIT MALLOCX_ARENA_LIMIT
|
||||||
|
#define DEFAULT_NUM_BACKGROUND_THREAD 4
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
background_thread_stopped,
|
background_thread_stopped,
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "jemalloc/internal/jemalloc_internal_types.h"
|
#include "jemalloc/internal/jemalloc_internal_types.h"
|
||||||
#include "jemalloc/internal/mutex.h"
|
#include "jemalloc/internal/mutex.h"
|
||||||
#include "jemalloc/internal/size_classes.h"
|
#include "jemalloc/internal/sc.h"
|
||||||
|
|
||||||
/* Embedded at the beginning of every block of base-managed virtual memory. */
|
/* Embedded at the beginning of every block of base-managed virtual memory. */
|
||||||
struct base_block_s {
|
struct base_block_s {
|
||||||
@ -46,7 +46,7 @@ struct base_s {
|
|||||||
base_block_t *blocks;
|
base_block_t *blocks;
|
||||||
|
|
||||||
/* Heap of extents that track unused trailing space within blocks. */
|
/* Heap of extents that track unused trailing space within blocks. */
|
||||||
extent_heap_t avail[NSIZES];
|
extent_heap_t avail[SC_NSIZES];
|
||||||
|
|
||||||
/* Stats, only maintained if config_stats. */
|
/* Stats, only maintained if config_stats. */
|
||||||
size_t allocated;
|
size_t allocated;
|
||||||
|
25
deps/jemalloc/include/jemalloc/internal/bin.h
vendored
25
deps/jemalloc/include/jemalloc/internal/bin.h
vendored
@ -1,10 +1,12 @@
|
|||||||
#ifndef JEMALLOC_INTERNAL_BIN_H
|
#ifndef JEMALLOC_INTERNAL_BIN_H
|
||||||
#define JEMALLOC_INTERNAL_BIN_H
|
#define JEMALLOC_INTERNAL_BIN_H
|
||||||
|
|
||||||
|
#include "jemalloc/internal/bin_stats.h"
|
||||||
|
#include "jemalloc/internal/bin_types.h"
|
||||||
#include "jemalloc/internal/extent_types.h"
|
#include "jemalloc/internal/extent_types.h"
|
||||||
#include "jemalloc/internal/extent_structs.h"
|
#include "jemalloc/internal/extent_structs.h"
|
||||||
#include "jemalloc/internal/mutex.h"
|
#include "jemalloc/internal/mutex.h"
|
||||||
#include "jemalloc/internal/bin_stats.h"
|
#include "jemalloc/internal/sc.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A bin contains a set of extents that are currently being used for slab
|
* A bin contains a set of extents that are currently being used for slab
|
||||||
@ -41,6 +43,9 @@ struct bin_info_s {
|
|||||||
/* Total number of regions in a slab for this bin's size class. */
|
/* Total number of regions in a slab for this bin's size class. */
|
||||||
uint32_t nregs;
|
uint32_t nregs;
|
||||||
|
|
||||||
|
/* Number of sharded bins in each arena for this size class. */
|
||||||
|
uint32_t n_shards;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Metadata used to manipulate bitmaps for slabs associated with this
|
* Metadata used to manipulate bitmaps for slabs associated with this
|
||||||
* bin.
|
* bin.
|
||||||
@ -48,8 +53,7 @@ struct bin_info_s {
|
|||||||
bitmap_info_t bitmap_info;
|
bitmap_info_t bitmap_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const bin_info_t bin_infos[NBINS];
|
extern bin_info_t bin_infos[SC_NBINS];
|
||||||
|
|
||||||
|
|
||||||
typedef struct bin_s bin_t;
|
typedef struct bin_s bin_t;
|
||||||
struct bin_s {
|
struct bin_s {
|
||||||
@ -78,6 +82,18 @@ struct bin_s {
|
|||||||
bin_stats_t stats;
|
bin_stats_t stats;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* A set of sharded bins of the same size class. */
|
||||||
|
typedef struct bins_s bins_t;
|
||||||
|
struct bins_s {
|
||||||
|
/* Sharded bins. Dynamically sized. */
|
||||||
|
bin_t *bin_shards;
|
||||||
|
};
|
||||||
|
|
||||||
|
void bin_shard_sizes_boot(unsigned bin_shards[SC_NBINS]);
|
||||||
|
bool bin_update_shard_size(unsigned bin_shards[SC_NBINS], size_t start_size,
|
||||||
|
size_t end_size, size_t nshards);
|
||||||
|
void bin_boot(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]);
|
||||||
|
|
||||||
/* Initializes a bin to empty. Returns true on error. */
|
/* Initializes a bin to empty. Returns true on error. */
|
||||||
bool bin_init(bin_t *bin);
|
bool bin_init(bin_t *bin);
|
||||||
|
|
||||||
@ -90,7 +106,7 @@ void bin_postfork_child(tsdn_t *tsdn, bin_t *bin);
|
|||||||
static inline void
|
static inline void
|
||||||
bin_stats_merge(tsdn_t *tsdn, bin_stats_t *dst_bin_stats, bin_t *bin) {
|
bin_stats_merge(tsdn_t *tsdn, bin_stats_t *dst_bin_stats, bin_t *bin) {
|
||||||
malloc_mutex_lock(tsdn, &bin->lock);
|
malloc_mutex_lock(tsdn, &bin->lock);
|
||||||
malloc_mutex_prof_read(tsdn, &dst_bin_stats->mutex_data, &bin->lock);
|
malloc_mutex_prof_accum(tsdn, &dst_bin_stats->mutex_data, &bin->lock);
|
||||||
dst_bin_stats->nmalloc += bin->stats.nmalloc;
|
dst_bin_stats->nmalloc += bin->stats.nmalloc;
|
||||||
dst_bin_stats->ndalloc += bin->stats.ndalloc;
|
dst_bin_stats->ndalloc += bin->stats.ndalloc;
|
||||||
dst_bin_stats->nrequests += bin->stats.nrequests;
|
dst_bin_stats->nrequests += bin->stats.nrequests;
|
||||||
@ -100,6 +116,7 @@ bin_stats_merge(tsdn_t *tsdn, bin_stats_t *dst_bin_stats, bin_t *bin) {
|
|||||||
dst_bin_stats->nslabs += bin->stats.nslabs;
|
dst_bin_stats->nslabs += bin->stats.nslabs;
|
||||||
dst_bin_stats->reslabs += bin->stats.reslabs;
|
dst_bin_stats->reslabs += bin->stats.reslabs;
|
||||||
dst_bin_stats->curslabs += bin->stats.curslabs;
|
dst_bin_stats->curslabs += bin->stats.curslabs;
|
||||||
|
dst_bin_stats->nonfull_slabs += bin->stats.nonfull_slabs;
|
||||||
malloc_mutex_unlock(tsdn, &bin->lock);
|
malloc_mutex_unlock(tsdn, &bin->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +45,9 @@ struct bin_stats_s {
|
|||||||
/* Current number of slabs in this bin. */
|
/* Current number of slabs in this bin. */
|
||||||
size_t curslabs;
|
size_t curslabs;
|
||||||
|
|
||||||
|
/* Current size of nonfull slabs heap in this bin. */
|
||||||
|
size_t nonfull_slabs;
|
||||||
|
|
||||||
mutex_prof_data_t mutex_data;
|
mutex_prof_data_t mutex_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
17
deps/jemalloc/include/jemalloc/internal/bin_types.h
vendored
Normal file
17
deps/jemalloc/include/jemalloc/internal/bin_types.h
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#ifndef JEMALLOC_INTERNAL_BIN_TYPES_H
|
||||||
|
#define JEMALLOC_INTERNAL_BIN_TYPES_H
|
||||||
|
|
||||||
|
#include "jemalloc/internal/sc.h"
|
||||||
|
|
||||||
|
#define BIN_SHARDS_MAX (1 << EXTENT_BITS_BINSHARD_WIDTH)
|
||||||
|
#define N_BIN_SHARDS_DEFAULT 1
|
||||||
|
|
||||||
|
/* Used in TSD static initializer only. Real init in arena_bind(). */
|
||||||
|
#define TSD_BINSHARDS_ZERO_INITIALIZER {{UINT8_MAX}}
|
||||||
|
|
||||||
|
typedef struct tsd_binshards_s tsd_binshards_t;
|
||||||
|
struct tsd_binshards_s {
|
||||||
|
uint8_t binshard[SC_NBINS];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_INTERNAL_BIN_TYPES_H */
|
@ -27,6 +27,25 @@ ffs_u(unsigned bitmap) {
|
|||||||
return JEMALLOC_INTERNAL_FFS(bitmap);
|
return JEMALLOC_INTERNAL_FFS(bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_INTERNAL_POPCOUNTL
|
||||||
|
BIT_UTIL_INLINE unsigned
|
||||||
|
popcount_lu(unsigned long bitmap) {
|
||||||
|
return JEMALLOC_INTERNAL_POPCOUNTL(bitmap);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clears first unset bit in bitmap, and returns
|
||||||
|
* place of bit. bitmap *must not* be 0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
BIT_UTIL_INLINE size_t
|
||||||
|
cfs_lu(unsigned long* bitmap) {
|
||||||
|
size_t bit = ffs_lu(*bitmap) - 1;
|
||||||
|
*bitmap ^= ZU(1) << bit;
|
||||||
|
return bit;
|
||||||
|
}
|
||||||
|
|
||||||
BIT_UTIL_INLINE unsigned
|
BIT_UTIL_INLINE unsigned
|
||||||
ffs_zu(size_t bitmap) {
|
ffs_zu(size_t bitmap) {
|
||||||
#if LG_SIZEOF_PTR == LG_SIZEOF_INT
|
#if LG_SIZEOF_PTR == LG_SIZEOF_INT
|
||||||
@ -63,6 +82,22 @@ ffs_u32(uint32_t bitmap) {
|
|||||||
|
|
||||||
BIT_UTIL_INLINE uint64_t
|
BIT_UTIL_INLINE uint64_t
|
||||||
pow2_ceil_u64(uint64_t x) {
|
pow2_ceil_u64(uint64_t x) {
|
||||||
|
#if (defined(__amd64__) || defined(__x86_64__) || defined(JEMALLOC_HAVE_BUILTIN_CLZ))
|
||||||
|
if(unlikely(x <= 1)) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
size_t msb_on_index;
|
||||||
|
#if (defined(__amd64__) || defined(__x86_64__))
|
||||||
|
asm ("bsrq %1, %0"
|
||||||
|
: "=r"(msb_on_index) // Outputs.
|
||||||
|
: "r"(x-1) // Inputs.
|
||||||
|
);
|
||||||
|
#elif (defined(JEMALLOC_HAVE_BUILTIN_CLZ))
|
||||||
|
msb_on_index = (63 ^ __builtin_clzll(x - 1));
|
||||||
|
#endif
|
||||||
|
assert(msb_on_index < 63);
|
||||||
|
return 1ULL << (msb_on_index + 1);
|
||||||
|
#else
|
||||||
x--;
|
x--;
|
||||||
x |= x >> 1;
|
x |= x >> 1;
|
||||||
x |= x >> 2;
|
x |= x >> 2;
|
||||||
@ -72,10 +107,27 @@ pow2_ceil_u64(uint64_t x) {
|
|||||||
x |= x >> 32;
|
x |= x >> 32;
|
||||||
x++;
|
x++;
|
||||||
return x;
|
return x;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
BIT_UTIL_INLINE uint32_t
|
BIT_UTIL_INLINE uint32_t
|
||||||
pow2_ceil_u32(uint32_t x) {
|
pow2_ceil_u32(uint32_t x) {
|
||||||
|
#if ((defined(__i386__) || defined(JEMALLOC_HAVE_BUILTIN_CLZ)) && (!defined(__s390__)))
|
||||||
|
if(unlikely(x <= 1)) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
size_t msb_on_index;
|
||||||
|
#if (defined(__i386__))
|
||||||
|
asm ("bsr %1, %0"
|
||||||
|
: "=r"(msb_on_index) // Outputs.
|
||||||
|
: "r"(x-1) // Inputs.
|
||||||
|
);
|
||||||
|
#elif (defined(JEMALLOC_HAVE_BUILTIN_CLZ))
|
||||||
|
msb_on_index = (31 ^ __builtin_clz(x - 1));
|
||||||
|
#endif
|
||||||
|
assert(msb_on_index < 31);
|
||||||
|
return 1U << (msb_on_index + 1);
|
||||||
|
#else
|
||||||
x--;
|
x--;
|
||||||
x |= x >> 1;
|
x |= x >> 1;
|
||||||
x |= x >> 2;
|
x |= x >> 2;
|
||||||
@ -84,6 +136,7 @@ pow2_ceil_u32(uint32_t x) {
|
|||||||
x |= x >> 16;
|
x |= x >> 16;
|
||||||
x++;
|
x++;
|
||||||
return x;
|
return x;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute the smallest power of 2 that is >= x. */
|
/* Compute the smallest power of 2 that is >= x. */
|
||||||
@ -160,6 +213,27 @@ lg_floor(size_t x) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
BIT_UTIL_INLINE unsigned
|
||||||
|
lg_ceil(size_t x) {
|
||||||
|
return lg_floor(x) + ((x & (x - 1)) == 0 ? 0 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
#undef BIT_UTIL_INLINE
|
#undef BIT_UTIL_INLINE
|
||||||
|
|
||||||
|
/* A compile-time version of lg_floor and lg_ceil. */
|
||||||
|
#define LG_FLOOR_1(x) 0
|
||||||
|
#define LG_FLOOR_2(x) (x < (1ULL << 1) ? LG_FLOOR_1(x) : 1 + LG_FLOOR_1(x >> 1))
|
||||||
|
#define LG_FLOOR_4(x) (x < (1ULL << 2) ? LG_FLOOR_2(x) : 2 + LG_FLOOR_2(x >> 2))
|
||||||
|
#define LG_FLOOR_8(x) (x < (1ULL << 4) ? LG_FLOOR_4(x) : 4 + LG_FLOOR_4(x >> 4))
|
||||||
|
#define LG_FLOOR_16(x) (x < (1ULL << 8) ? LG_FLOOR_8(x) : 8 + LG_FLOOR_8(x >> 8))
|
||||||
|
#define LG_FLOOR_32(x) (x < (1ULL << 16) ? LG_FLOOR_16(x) : 16 + LG_FLOOR_16(x >> 16))
|
||||||
|
#define LG_FLOOR_64(x) (x < (1ULL << 32) ? LG_FLOOR_32(x) : 32 + LG_FLOOR_32(x >> 32))
|
||||||
|
#if LG_SIZEOF_PTR == 2
|
||||||
|
# define LG_FLOOR(x) LG_FLOOR_32((x))
|
||||||
|
#else
|
||||||
|
# define LG_FLOOR(x) LG_FLOOR_64((x))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define LG_CEIL(x) (LG_FLOOR(x) + (((x) & ((x) - 1)) == 0 ? 0 : 1))
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_BIT_UTIL_H */
|
#endif /* JEMALLOC_INTERNAL_BIT_UTIL_H */
|
||||||
|
@ -3,18 +3,18 @@
|
|||||||
|
|
||||||
#include "jemalloc/internal/arena_types.h"
|
#include "jemalloc/internal/arena_types.h"
|
||||||
#include "jemalloc/internal/bit_util.h"
|
#include "jemalloc/internal/bit_util.h"
|
||||||
#include "jemalloc/internal/size_classes.h"
|
#include "jemalloc/internal/sc.h"
|
||||||
|
|
||||||
typedef unsigned long bitmap_t;
|
typedef unsigned long bitmap_t;
|
||||||
#define LG_SIZEOF_BITMAP LG_SIZEOF_LONG
|
#define LG_SIZEOF_BITMAP LG_SIZEOF_LONG
|
||||||
|
|
||||||
/* Maximum bitmap bit count is 2^LG_BITMAP_MAXBITS. */
|
/* Maximum bitmap bit count is 2^LG_BITMAP_MAXBITS. */
|
||||||
#if LG_SLAB_MAXREGS > LG_CEIL_NSIZES
|
#if LG_SLAB_MAXREGS > LG_CEIL(SC_NSIZES)
|
||||||
/* Maximum bitmap bit count is determined by maximum regions per slab. */
|
/* Maximum bitmap bit count is determined by maximum regions per slab. */
|
||||||
# define LG_BITMAP_MAXBITS LG_SLAB_MAXREGS
|
# define LG_BITMAP_MAXBITS LG_SLAB_MAXREGS
|
||||||
#else
|
#else
|
||||||
/* Maximum bitmap bit count is determined by number of extent size classes. */
|
/* Maximum bitmap bit count is determined by number of extent size classes. */
|
||||||
# define LG_BITMAP_MAXBITS LG_CEIL_NSIZES
|
# define LG_BITMAP_MAXBITS LG_CEIL(SC_NSIZES)
|
||||||
#endif
|
#endif
|
||||||
#define BITMAP_MAXBITS (ZU(1) << LG_BITMAP_MAXBITS)
|
#define BITMAP_MAXBITS (ZU(1) << LG_BITMAP_MAXBITS)
|
||||||
|
|
||||||
|
@ -88,11 +88,21 @@ JEMALLOC_ALWAYS_INLINE void *
|
|||||||
cache_bin_alloc_easy(cache_bin_t *bin, bool *success) {
|
cache_bin_alloc_easy(cache_bin_t *bin, bool *success) {
|
||||||
void *ret;
|
void *ret;
|
||||||
|
|
||||||
if (unlikely(bin->ncached == 0)) {
|
bin->ncached--;
|
||||||
bin->low_water = -1;
|
|
||||||
|
/*
|
||||||
|
* Check for both bin->ncached == 0 and ncached < low_water
|
||||||
|
* in a single branch.
|
||||||
|
*/
|
||||||
|
if (unlikely(bin->ncached <= bin->low_water)) {
|
||||||
|
bin->low_water = bin->ncached;
|
||||||
|
if (bin->ncached == -1) {
|
||||||
|
bin->ncached = 0;
|
||||||
*success = false;
|
*success = false;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* success (instead of ret) should be checked upon the return of this
|
* success (instead of ret) should be checked upon the return of this
|
||||||
* function. We avoid checking (ret == NULL) because there is never a
|
* function. We avoid checking (ret == NULL) because there is never a
|
||||||
@ -101,14 +111,21 @@ cache_bin_alloc_easy(cache_bin_t *bin, bool *success) {
|
|||||||
* cacheline).
|
* cacheline).
|
||||||
*/
|
*/
|
||||||
*success = true;
|
*success = true;
|
||||||
ret = *(bin->avail - bin->ncached);
|
ret = *(bin->avail - (bin->ncached + 1));
|
||||||
bin->ncached--;
|
|
||||||
|
|
||||||
if (unlikely(bin->ncached < bin->low_water)) {
|
|
||||||
bin->low_water = bin->ncached;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JEMALLOC_ALWAYS_INLINE bool
|
||||||
|
cache_bin_dalloc_easy(cache_bin_t *bin, cache_bin_info_t *bin_info, void *ptr) {
|
||||||
|
if (unlikely(bin->ncached == bin_info->ncached_max)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
assert(bin->ncached < bin_info->ncached_max);
|
||||||
|
bin->ncached++;
|
||||||
|
*(bin->avail - bin->ncached) = ptr;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_CACHE_BIN_H */
|
#endif /* JEMALLOC_INTERNAL_CACHE_BIN_H */
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#include "jemalloc/internal/malloc_io.h"
|
#include "jemalloc/internal/malloc_io.h"
|
||||||
#include "jemalloc/internal/mutex_prof.h"
|
#include "jemalloc/internal/mutex_prof.h"
|
||||||
#include "jemalloc/internal/ql.h"
|
#include "jemalloc/internal/ql.h"
|
||||||
#include "jemalloc/internal/size_classes.h"
|
#include "jemalloc/internal/sc.h"
|
||||||
#include "jemalloc/internal/stats.h"
|
#include "jemalloc/internal/stats.h"
|
||||||
|
|
||||||
/* Maximum ctl tree depth. */
|
/* Maximum ctl tree depth. */
|
||||||
@ -39,9 +39,12 @@ typedef struct ctl_arena_stats_s {
|
|||||||
uint64_t nmalloc_small;
|
uint64_t nmalloc_small;
|
||||||
uint64_t ndalloc_small;
|
uint64_t ndalloc_small;
|
||||||
uint64_t nrequests_small;
|
uint64_t nrequests_small;
|
||||||
|
uint64_t nfills_small;
|
||||||
|
uint64_t nflushes_small;
|
||||||
|
|
||||||
bin_stats_t bstats[NBINS];
|
bin_stats_t bstats[SC_NBINS];
|
||||||
arena_stats_large_t lstats[NSIZES - NBINS];
|
arena_stats_large_t lstats[SC_NSIZES - SC_NBINS];
|
||||||
|
arena_stats_extents_t estats[SC_NPSIZES];
|
||||||
} ctl_arena_stats_t;
|
} ctl_arena_stats_t;
|
||||||
|
|
||||||
typedef struct ctl_stats_s {
|
typedef struct ctl_stats_s {
|
||||||
|
435
deps/jemalloc/include/jemalloc/internal/emitter.h
vendored
435
deps/jemalloc/include/jemalloc/internal/emitter.h
vendored
@ -45,7 +45,9 @@ struct emitter_col_s {
|
|||||||
int int_val;
|
int int_val;
|
||||||
unsigned unsigned_val;
|
unsigned unsigned_val;
|
||||||
uint32_t uint32_val;
|
uint32_t uint32_val;
|
||||||
|
uint32_t uint32_t_val;
|
||||||
uint64_t uint64_val;
|
uint64_t uint64_val;
|
||||||
|
uint64_t uint64_t_val;
|
||||||
size_t size_val;
|
size_t size_val;
|
||||||
ssize_t ssize_val;
|
ssize_t ssize_val;
|
||||||
const char *str_val;
|
const char *str_val;
|
||||||
@ -60,17 +62,6 @@ struct emitter_row_s {
|
|||||||
ql_head(emitter_col_t) cols;
|
ql_head(emitter_col_t) cols;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void
|
|
||||||
emitter_row_init(emitter_row_t *row) {
|
|
||||||
ql_new(&row->cols);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
emitter_col_init(emitter_col_t *col, emitter_row_t *row) {
|
|
||||||
ql_elm_new(col, link);
|
|
||||||
ql_tail_insert(&row->cols, col, link);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct emitter_s emitter_t;
|
typedef struct emitter_s emitter_t;
|
||||||
struct emitter_s {
|
struct emitter_s {
|
||||||
emitter_output_t output;
|
emitter_output_t output;
|
||||||
@ -80,18 +71,10 @@ struct emitter_s {
|
|||||||
int nesting_depth;
|
int nesting_depth;
|
||||||
/* True if we've already emitted a value at the given depth. */
|
/* True if we've already emitted a value at the given depth. */
|
||||||
bool item_at_depth;
|
bool item_at_depth;
|
||||||
|
/* True if we emitted a key and will emit corresponding value next. */
|
||||||
|
bool emitted_key;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void
|
|
||||||
emitter_init(emitter_t *emitter, emitter_output_t emitter_output,
|
|
||||||
void (*write_cb)(void *, const char *), void *cbopaque) {
|
|
||||||
emitter->output = emitter_output;
|
|
||||||
emitter->write_cb = write_cb;
|
|
||||||
emitter->cbopaque = cbopaque;
|
|
||||||
emitter->item_at_depth = false;
|
|
||||||
emitter->nesting_depth = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Internal convenience function. Write to the emitter the given string. */
|
/* Internal convenience function. Write to the emitter the given string. */
|
||||||
JEMALLOC_FORMAT_PRINTF(2, 3)
|
JEMALLOC_FORMAT_PRINTF(2, 3)
|
||||||
static inline void
|
static inline void
|
||||||
@ -103,22 +86,11 @@ emitter_printf(emitter_t *emitter, const char *format, ...) {
|
|||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write to the emitter the given string, but only in table mode. */
|
static inline const char * JEMALLOC_FORMAT_ARG(3)
|
||||||
JEMALLOC_FORMAT_PRINTF(2, 3)
|
|
||||||
static inline void
|
|
||||||
emitter_table_printf(emitter_t *emitter, const char *format, ...) {
|
|
||||||
if (emitter->output == emitter_output_table) {
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap, format);
|
|
||||||
malloc_vcprintf(emitter->write_cb, emitter->cbopaque, format, ap);
|
|
||||||
va_end(ap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
emitter_gen_fmt(char *out_fmt, size_t out_size, const char *fmt_specifier,
|
emitter_gen_fmt(char *out_fmt, size_t out_size, const char *fmt_specifier,
|
||||||
emitter_justify_t justify, int width) {
|
emitter_justify_t justify, int width) {
|
||||||
size_t written;
|
size_t written;
|
||||||
|
fmt_specifier++;
|
||||||
if (justify == emitter_justify_none) {
|
if (justify == emitter_justify_none) {
|
||||||
written = malloc_snprintf(out_fmt, out_size,
|
written = malloc_snprintf(out_fmt, out_size,
|
||||||
"%%%s", fmt_specifier);
|
"%%%s", fmt_specifier);
|
||||||
@ -131,6 +103,7 @@ emitter_gen_fmt(char *out_fmt, size_t out_size, const char *fmt_specifier,
|
|||||||
}
|
}
|
||||||
/* Only happens in case of bad format string, which *we* choose. */
|
/* Only happens in case of bad format string, which *we* choose. */
|
||||||
assert(written < out_size);
|
assert(written < out_size);
|
||||||
|
return out_fmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -156,26 +129,27 @@ emitter_print_value(emitter_t *emitter, emitter_justify_t justify, int width,
|
|||||||
char buf[BUF_SIZE];
|
char buf[BUF_SIZE];
|
||||||
|
|
||||||
#define EMIT_SIMPLE(type, format) \
|
#define EMIT_SIMPLE(type, format) \
|
||||||
emitter_gen_fmt(fmt, FMT_SIZE, format, justify, width); \
|
emitter_printf(emitter, \
|
||||||
emitter_printf(emitter, fmt, *(const type *)value); \
|
emitter_gen_fmt(fmt, FMT_SIZE, format, justify, width), \
|
||||||
|
*(const type *)value);
|
||||||
|
|
||||||
switch (value_type) {
|
switch (value_type) {
|
||||||
case emitter_type_bool:
|
case emitter_type_bool:
|
||||||
emitter_gen_fmt(fmt, FMT_SIZE, "s", justify, width);
|
emitter_printf(emitter,
|
||||||
emitter_printf(emitter, fmt, *(const bool *)value ?
|
emitter_gen_fmt(fmt, FMT_SIZE, "%s", justify, width),
|
||||||
"true" : "false");
|
*(const bool *)value ? "true" : "false");
|
||||||
break;
|
break;
|
||||||
case emitter_type_int:
|
case emitter_type_int:
|
||||||
EMIT_SIMPLE(int, "d")
|
EMIT_SIMPLE(int, "%d")
|
||||||
break;
|
break;
|
||||||
case emitter_type_unsigned:
|
case emitter_type_unsigned:
|
||||||
EMIT_SIMPLE(unsigned, "u")
|
EMIT_SIMPLE(unsigned, "%u")
|
||||||
break;
|
break;
|
||||||
case emitter_type_ssize:
|
case emitter_type_ssize:
|
||||||
EMIT_SIMPLE(ssize_t, "zd")
|
EMIT_SIMPLE(ssize_t, "%zd")
|
||||||
break;
|
break;
|
||||||
case emitter_type_size:
|
case emitter_type_size:
|
||||||
EMIT_SIMPLE(size_t, "zu")
|
EMIT_SIMPLE(size_t, "%zu")
|
||||||
break;
|
break;
|
||||||
case emitter_type_string:
|
case emitter_type_string:
|
||||||
str_written = malloc_snprintf(buf, BUF_SIZE, "\"%s\"",
|
str_written = malloc_snprintf(buf, BUF_SIZE, "\"%s\"",
|
||||||
@ -185,17 +159,17 @@ emitter_print_value(emitter_t *emitter, emitter_justify_t justify, int width,
|
|||||||
* anywhere near the fmt size.
|
* anywhere near the fmt size.
|
||||||
*/
|
*/
|
||||||
assert(str_written < BUF_SIZE);
|
assert(str_written < BUF_SIZE);
|
||||||
emitter_gen_fmt(fmt, FMT_SIZE, "s", justify, width);
|
emitter_printf(emitter,
|
||||||
emitter_printf(emitter, fmt, buf);
|
emitter_gen_fmt(fmt, FMT_SIZE, "%s", justify, width), buf);
|
||||||
break;
|
break;
|
||||||
case emitter_type_uint32:
|
case emitter_type_uint32:
|
||||||
EMIT_SIMPLE(uint32_t, FMTu32)
|
EMIT_SIMPLE(uint32_t, "%" FMTu32)
|
||||||
break;
|
break;
|
||||||
case emitter_type_uint64:
|
case emitter_type_uint64:
|
||||||
EMIT_SIMPLE(uint64_t, FMTu64)
|
EMIT_SIMPLE(uint64_t, "%" FMTu64)
|
||||||
break;
|
break;
|
||||||
case emitter_type_title:
|
case emitter_type_title:
|
||||||
EMIT_SIMPLE(char *const, "s");
|
EMIT_SIMPLE(char *const, "%s");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
unreachable();
|
unreachable();
|
||||||
@ -235,47 +209,143 @@ emitter_indent(emitter_t *emitter) {
|
|||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
emitter_json_key_prefix(emitter_t *emitter) {
|
emitter_json_key_prefix(emitter_t *emitter) {
|
||||||
|
if (emitter->emitted_key) {
|
||||||
|
emitter->emitted_key = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
emitter_printf(emitter, "%s\n", emitter->item_at_depth ? "," : "");
|
emitter_printf(emitter, "%s\n", emitter->item_at_depth ? "," : "");
|
||||||
emitter_indent(emitter);
|
emitter_indent(emitter);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
/******************************************************************************/
|
||||||
emitter_begin(emitter_t *emitter) {
|
/* Public functions for emitter_t. */
|
||||||
if (emitter->output == emitter_output_json) {
|
|
||||||
assert(emitter->nesting_depth == 0);
|
|
||||||
emitter_printf(emitter, "{");
|
|
||||||
emitter_nest_inc(emitter);
|
|
||||||
} else {
|
|
||||||
// tabular init
|
|
||||||
emitter_printf(emitter, "%s", "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
emitter_end(emitter_t *emitter) {
|
emitter_init(emitter_t *emitter, emitter_output_t emitter_output,
|
||||||
if (emitter->output == emitter_output_json) {
|
void (*write_cb)(void *, const char *), void *cbopaque) {
|
||||||
assert(emitter->nesting_depth == 1);
|
emitter->output = emitter_output;
|
||||||
emitter_nest_dec(emitter);
|
emitter->write_cb = write_cb;
|
||||||
emitter_printf(emitter, "\n}\n");
|
emitter->cbopaque = cbopaque;
|
||||||
}
|
emitter->item_at_depth = false;
|
||||||
|
emitter->emitted_key = false;
|
||||||
|
emitter->nesting_depth = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/* JSON public API. */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note emits a different kv pair as well, but only in table mode. Omits the
|
* Emits a key (e.g. as appears in an object). The next json entity emitted will
|
||||||
* note if table_note_key is NULL.
|
* be the corresponding value.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
emitter_kv_note(emitter_t *emitter, const char *json_key, const char *table_key,
|
emitter_json_key(emitter_t *emitter, const char *json_key) {
|
||||||
|
if (emitter->output == emitter_output_json) {
|
||||||
|
emitter_json_key_prefix(emitter);
|
||||||
|
emitter_printf(emitter, "\"%s\": ", json_key);
|
||||||
|
emitter->emitted_key = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
emitter_json_value(emitter_t *emitter, emitter_type_t value_type,
|
||||||
|
const void *value) {
|
||||||
|
if (emitter->output == emitter_output_json) {
|
||||||
|
emitter_json_key_prefix(emitter);
|
||||||
|
emitter_print_value(emitter, emitter_justify_none, -1,
|
||||||
|
value_type, value);
|
||||||
|
emitter->item_at_depth = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shorthand for calling emitter_json_key and then emitter_json_value. */
|
||||||
|
static inline void
|
||||||
|
emitter_json_kv(emitter_t *emitter, const char *json_key,
|
||||||
|
emitter_type_t value_type, const void *value) {
|
||||||
|
emitter_json_key(emitter, json_key);
|
||||||
|
emitter_json_value(emitter, value_type, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
emitter_json_array_begin(emitter_t *emitter) {
|
||||||
|
if (emitter->output == emitter_output_json) {
|
||||||
|
emitter_json_key_prefix(emitter);
|
||||||
|
emitter_printf(emitter, "[");
|
||||||
|
emitter_nest_inc(emitter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shorthand for calling emitter_json_key and then emitter_json_array_begin. */
|
||||||
|
static inline void
|
||||||
|
emitter_json_array_kv_begin(emitter_t *emitter, const char *json_key) {
|
||||||
|
emitter_json_key(emitter, json_key);
|
||||||
|
emitter_json_array_begin(emitter);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
emitter_json_array_end(emitter_t *emitter) {
|
||||||
|
if (emitter->output == emitter_output_json) {
|
||||||
|
assert(emitter->nesting_depth > 0);
|
||||||
|
emitter_nest_dec(emitter);
|
||||||
|
emitter_printf(emitter, "\n");
|
||||||
|
emitter_indent(emitter);
|
||||||
|
emitter_printf(emitter, "]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
emitter_json_object_begin(emitter_t *emitter) {
|
||||||
|
if (emitter->output == emitter_output_json) {
|
||||||
|
emitter_json_key_prefix(emitter);
|
||||||
|
emitter_printf(emitter, "{");
|
||||||
|
emitter_nest_inc(emitter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shorthand for calling emitter_json_key and then emitter_json_object_begin. */
|
||||||
|
static inline void
|
||||||
|
emitter_json_object_kv_begin(emitter_t *emitter, const char *json_key) {
|
||||||
|
emitter_json_key(emitter, json_key);
|
||||||
|
emitter_json_object_begin(emitter);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
emitter_json_object_end(emitter_t *emitter) {
|
||||||
|
if (emitter->output == emitter_output_json) {
|
||||||
|
assert(emitter->nesting_depth > 0);
|
||||||
|
emitter_nest_dec(emitter);
|
||||||
|
emitter_printf(emitter, "\n");
|
||||||
|
emitter_indent(emitter);
|
||||||
|
emitter_printf(emitter, "}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/* Table public API. */
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
emitter_table_dict_begin(emitter_t *emitter, const char *table_key) {
|
||||||
|
if (emitter->output == emitter_output_table) {
|
||||||
|
emitter_indent(emitter);
|
||||||
|
emitter_printf(emitter, "%s\n", table_key);
|
||||||
|
emitter_nest_inc(emitter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
emitter_table_dict_end(emitter_t *emitter) {
|
||||||
|
if (emitter->output == emitter_output_table) {
|
||||||
|
emitter_nest_dec(emitter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
emitter_table_kv_note(emitter_t *emitter, const char *table_key,
|
||||||
emitter_type_t value_type, const void *value,
|
emitter_type_t value_type, const void *value,
|
||||||
const char *table_note_key, emitter_type_t table_note_value_type,
|
const char *table_note_key, emitter_type_t table_note_value_type,
|
||||||
const void *table_note_value) {
|
const void *table_note_value) {
|
||||||
if (emitter->output == emitter_output_json) {
|
if (emitter->output == emitter_output_table) {
|
||||||
assert(emitter->nesting_depth > 0);
|
|
||||||
emitter_json_key_prefix(emitter);
|
|
||||||
emitter_printf(emitter, "\"%s\": ", json_key);
|
|
||||||
emitter_print_value(emitter, emitter_justify_none, -1,
|
|
||||||
value_type, value);
|
|
||||||
} else {
|
|
||||||
emitter_indent(emitter);
|
emitter_indent(emitter);
|
||||||
emitter_printf(emitter, "%s: ", table_key);
|
emitter_printf(emitter, "%s: ", table_key);
|
||||||
emitter_print_value(emitter, emitter_justify_none, -1,
|
emitter_print_value(emitter, emitter_justify_none, -1,
|
||||||
@ -292,130 +362,22 @@ emitter_kv_note(emitter_t *emitter, const char *json_key, const char *table_key,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
emitter_kv(emitter_t *emitter, const char *json_key, const char *table_key,
|
emitter_table_kv(emitter_t *emitter, const char *table_key,
|
||||||
emitter_type_t value_type, const void *value) {
|
emitter_type_t value_type, const void *value) {
|
||||||
emitter_kv_note(emitter, json_key, table_key, value_type, value, NULL,
|
emitter_table_kv_note(emitter, table_key, value_type, value, NULL,
|
||||||
emitter_type_bool, NULL);
|
emitter_type_bool, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
|
||||||
emitter_json_kv(emitter_t *emitter, const char *json_key,
|
|
||||||
emitter_type_t value_type, const void *value) {
|
|
||||||
if (emitter->output == emitter_output_json) {
|
|
||||||
emitter_kv(emitter, json_key, NULL, value_type, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Write to the emitter the given string, but only in table mode. */
|
||||||
|
JEMALLOC_FORMAT_PRINTF(2, 3)
|
||||||
static inline void
|
static inline void
|
||||||
emitter_table_kv(emitter_t *emitter, const char *table_key,
|
emitter_table_printf(emitter_t *emitter, const char *format, ...) {
|
||||||
emitter_type_t value_type, const void *value) {
|
|
||||||
if (emitter->output == emitter_output_table) {
|
if (emitter->output == emitter_output_table) {
|
||||||
emitter_kv(emitter, NULL, table_key, value_type, value);
|
va_list ap;
|
||||||
}
|
va_start(ap, format);
|
||||||
}
|
malloc_vcprintf(emitter->write_cb, emitter->cbopaque, format, ap);
|
||||||
|
va_end(ap);
|
||||||
static inline void
|
|
||||||
emitter_dict_begin(emitter_t *emitter, const char *json_key,
|
|
||||||
const char *table_header) {
|
|
||||||
if (emitter->output == emitter_output_json) {
|
|
||||||
emitter_json_key_prefix(emitter);
|
|
||||||
emitter_printf(emitter, "\"%s\": {", json_key);
|
|
||||||
emitter_nest_inc(emitter);
|
|
||||||
} else {
|
|
||||||
emitter_indent(emitter);
|
|
||||||
emitter_printf(emitter, "%s\n", table_header);
|
|
||||||
emitter_nest_inc(emitter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
emitter_dict_end(emitter_t *emitter) {
|
|
||||||
if (emitter->output == emitter_output_json) {
|
|
||||||
assert(emitter->nesting_depth > 0);
|
|
||||||
emitter_nest_dec(emitter);
|
|
||||||
emitter_printf(emitter, "\n");
|
|
||||||
emitter_indent(emitter);
|
|
||||||
emitter_printf(emitter, "}");
|
|
||||||
} else {
|
|
||||||
emitter_nest_dec(emitter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
emitter_json_dict_begin(emitter_t *emitter, const char *json_key) {
|
|
||||||
if (emitter->output == emitter_output_json) {
|
|
||||||
emitter_dict_begin(emitter, json_key, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
emitter_json_dict_end(emitter_t *emitter) {
|
|
||||||
if (emitter->output == emitter_output_json) {
|
|
||||||
emitter_dict_end(emitter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
emitter_table_dict_begin(emitter_t *emitter, const char *table_key) {
|
|
||||||
if (emitter->output == emitter_output_table) {
|
|
||||||
emitter_dict_begin(emitter, NULL, table_key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
emitter_table_dict_end(emitter_t *emitter) {
|
|
||||||
if (emitter->output == emitter_output_table) {
|
|
||||||
emitter_dict_end(emitter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
emitter_json_arr_begin(emitter_t *emitter, const char *json_key) {
|
|
||||||
if (emitter->output == emitter_output_json) {
|
|
||||||
emitter_json_key_prefix(emitter);
|
|
||||||
emitter_printf(emitter, "\"%s\": [", json_key);
|
|
||||||
emitter_nest_inc(emitter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
emitter_json_arr_end(emitter_t *emitter) {
|
|
||||||
if (emitter->output == emitter_output_json) {
|
|
||||||
assert(emitter->nesting_depth > 0);
|
|
||||||
emitter_nest_dec(emitter);
|
|
||||||
emitter_printf(emitter, "\n");
|
|
||||||
emitter_indent(emitter);
|
|
||||||
emitter_printf(emitter, "]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
emitter_json_arr_obj_begin(emitter_t *emitter) {
|
|
||||||
if (emitter->output == emitter_output_json) {
|
|
||||||
emitter_json_key_prefix(emitter);
|
|
||||||
emitter_printf(emitter, "{");
|
|
||||||
emitter_nest_inc(emitter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
emitter_json_arr_obj_end(emitter_t *emitter) {
|
|
||||||
if (emitter->output == emitter_output_json) {
|
|
||||||
assert(emitter->nesting_depth > 0);
|
|
||||||
emitter_nest_dec(emitter);
|
|
||||||
emitter_printf(emitter, "\n");
|
|
||||||
emitter_indent(emitter);
|
|
||||||
emitter_printf(emitter, "}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
emitter_json_arr_value(emitter_t *emitter, emitter_type_t value_type,
|
|
||||||
const void *value) {
|
|
||||||
if (emitter->output == emitter_output_json) {
|
|
||||||
emitter_json_key_prefix(emitter);
|
|
||||||
emitter_print_value(emitter, emitter_justify_none, -1,
|
|
||||||
value_type, value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -432,4 +394,93 @@ emitter_table_row(emitter_t *emitter, emitter_row_t *row) {
|
|||||||
emitter_table_printf(emitter, "\n");
|
emitter_table_printf(emitter, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
emitter_row_init(emitter_row_t *row) {
|
||||||
|
ql_new(&row->cols);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
emitter_col_init(emitter_col_t *col, emitter_row_t *row) {
|
||||||
|
ql_elm_new(col, link);
|
||||||
|
ql_tail_insert(&row->cols, col, link);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*
|
||||||
|
* Generalized public API. Emits using either JSON or table, according to
|
||||||
|
* settings in the emitter_t. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note emits a different kv pair as well, but only in table mode. Omits the
|
||||||
|
* note if table_note_key is NULL.
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
emitter_kv_note(emitter_t *emitter, const char *json_key, const char *table_key,
|
||||||
|
emitter_type_t value_type, const void *value,
|
||||||
|
const char *table_note_key, emitter_type_t table_note_value_type,
|
||||||
|
const void *table_note_value) {
|
||||||
|
if (emitter->output == emitter_output_json) {
|
||||||
|
emitter_json_key(emitter, json_key);
|
||||||
|
emitter_json_value(emitter, value_type, value);
|
||||||
|
} else {
|
||||||
|
emitter_table_kv_note(emitter, table_key, value_type, value,
|
||||||
|
table_note_key, table_note_value_type, table_note_value);
|
||||||
|
}
|
||||||
|
emitter->item_at_depth = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
emitter_kv(emitter_t *emitter, const char *json_key, const char *table_key,
|
||||||
|
emitter_type_t value_type, const void *value) {
|
||||||
|
emitter_kv_note(emitter, json_key, table_key, value_type, value, NULL,
|
||||||
|
emitter_type_bool, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
emitter_dict_begin(emitter_t *emitter, const char *json_key,
|
||||||
|
const char *table_header) {
|
||||||
|
if (emitter->output == emitter_output_json) {
|
||||||
|
emitter_json_key(emitter, json_key);
|
||||||
|
emitter_json_object_begin(emitter);
|
||||||
|
} else {
|
||||||
|
emitter_table_dict_begin(emitter, table_header);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
emitter_dict_end(emitter_t *emitter) {
|
||||||
|
if (emitter->output == emitter_output_json) {
|
||||||
|
emitter_json_object_end(emitter);
|
||||||
|
} else {
|
||||||
|
emitter_table_dict_end(emitter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
emitter_begin(emitter_t *emitter) {
|
||||||
|
if (emitter->output == emitter_output_json) {
|
||||||
|
assert(emitter->nesting_depth == 0);
|
||||||
|
emitter_printf(emitter, "{");
|
||||||
|
emitter_nest_inc(emitter);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* This guarantees that we always call write_cb at least once.
|
||||||
|
* This is useful if some invariant is established by each call
|
||||||
|
* to write_cb, but doesn't hold initially: e.g., some buffer
|
||||||
|
* holds a null-terminated string.
|
||||||
|
*/
|
||||||
|
emitter_printf(emitter, "%s", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
emitter_end(emitter_t *emitter) {
|
||||||
|
if (emitter->output == emitter_output_json) {
|
||||||
|
assert(emitter->nesting_depth == 1);
|
||||||
|
emitter_nest_dec(emitter);
|
||||||
|
emitter_printf(emitter, "\n}\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_EMITTER_H */
|
#endif /* JEMALLOC_INTERNAL_EMITTER_H */
|
||||||
|
@ -24,13 +24,17 @@ size_t extent_size_quantize_floor(size_t size);
|
|||||||
size_t extent_size_quantize_ceil(size_t size);
|
size_t extent_size_quantize_ceil(size_t size);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
rb_proto(, extent_avail_, extent_tree_t, extent_t)
|
ph_proto(, extent_avail_, extent_tree_t, extent_t)
|
||||||
ph_proto(, extent_heap_, extent_heap_t, extent_t)
|
ph_proto(, extent_heap_, extent_heap_t, extent_t)
|
||||||
|
|
||||||
bool extents_init(tsdn_t *tsdn, extents_t *extents, extent_state_t state,
|
bool extents_init(tsdn_t *tsdn, extents_t *extents, extent_state_t state,
|
||||||
bool delay_coalesce);
|
bool delay_coalesce);
|
||||||
extent_state_t extents_state_get(const extents_t *extents);
|
extent_state_t extents_state_get(const extents_t *extents);
|
||||||
size_t extents_npages_get(extents_t *extents);
|
size_t extents_npages_get(extents_t *extents);
|
||||||
|
/* Get the number of extents in the given page size index. */
|
||||||
|
size_t extents_nextents_get(extents_t *extents, pszind_t ind);
|
||||||
|
/* Get the sum total bytes of the extents in the given page size index. */
|
||||||
|
size_t extents_nbytes_get(extents_t *extents, pszind_t ind);
|
||||||
extent_t *extents_alloc(tsdn_t *tsdn, arena_t *arena,
|
extent_t *extents_alloc(tsdn_t *tsdn, arena_t *arena,
|
||||||
extent_hooks_t **r_extent_hooks, extents_t *extents, void *new_addr,
|
extent_hooks_t **r_extent_hooks, extents_t *extents, void *new_addr,
|
||||||
size_t size, size_t pad, size_t alignment, bool slab, szind_t szind,
|
size_t size, size_t pad, size_t alignment, bool slab, szind_t szind,
|
||||||
@ -70,4 +74,10 @@ bool extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena,
|
|||||||
|
|
||||||
bool extent_boot(void);
|
bool extent_boot(void);
|
||||||
|
|
||||||
|
void extent_util_stats_get(tsdn_t *tsdn, const void *ptr,
|
||||||
|
size_t *nfree, size_t *nregs, size_t *size);
|
||||||
|
void extent_util_stats_verbose_get(tsdn_t *tsdn, const void *ptr,
|
||||||
|
size_t *nfree, size_t *nregs, size_t *size,
|
||||||
|
size_t *bin_nfree, size_t *bin_nregs, void **slabcur_addr);
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_EXTENT_EXTERNS_H */
|
#endif /* JEMALLOC_INTERNAL_EXTENT_EXTERNS_H */
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "jemalloc/internal/pages.h"
|
#include "jemalloc/internal/pages.h"
|
||||||
#include "jemalloc/internal/prng.h"
|
#include "jemalloc/internal/prng.h"
|
||||||
#include "jemalloc/internal/ql.h"
|
#include "jemalloc/internal/ql.h"
|
||||||
|
#include "jemalloc/internal/sc.h"
|
||||||
#include "jemalloc/internal/sz.h"
|
#include "jemalloc/internal/sz.h"
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
@ -34,18 +35,19 @@ extent_unlock2(tsdn_t *tsdn, extent_t *extent1, extent_t *extent2) {
|
|||||||
(uintptr_t)extent2);
|
(uintptr_t)extent2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline arena_t *
|
static inline unsigned
|
||||||
extent_arena_get(const extent_t *extent) {
|
extent_arena_ind_get(const extent_t *extent) {
|
||||||
unsigned arena_ind = (unsigned)((extent->e_bits &
|
unsigned arena_ind = (unsigned)((extent->e_bits &
|
||||||
EXTENT_BITS_ARENA_MASK) >> EXTENT_BITS_ARENA_SHIFT);
|
EXTENT_BITS_ARENA_MASK) >> EXTENT_BITS_ARENA_SHIFT);
|
||||||
/*
|
|
||||||
* The following check is omitted because we should never actually read
|
|
||||||
* a NULL arena pointer.
|
|
||||||
*/
|
|
||||||
if (false && arena_ind >= MALLOCX_ARENA_LIMIT) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
assert(arena_ind < MALLOCX_ARENA_LIMIT);
|
assert(arena_ind < MALLOCX_ARENA_LIMIT);
|
||||||
|
|
||||||
|
return arena_ind;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline arena_t *
|
||||||
|
extent_arena_get(const extent_t *extent) {
|
||||||
|
unsigned arena_ind = extent_arena_ind_get(extent);
|
||||||
|
|
||||||
return (arena_t *)atomic_load_p(&arenas[arena_ind], ATOMIC_ACQUIRE);
|
return (arena_t *)atomic_load_p(&arenas[arena_ind], ATOMIC_ACQUIRE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,14 +55,14 @@ static inline szind_t
|
|||||||
extent_szind_get_maybe_invalid(const extent_t *extent) {
|
extent_szind_get_maybe_invalid(const extent_t *extent) {
|
||||||
szind_t szind = (szind_t)((extent->e_bits & EXTENT_BITS_SZIND_MASK) >>
|
szind_t szind = (szind_t)((extent->e_bits & EXTENT_BITS_SZIND_MASK) >>
|
||||||
EXTENT_BITS_SZIND_SHIFT);
|
EXTENT_BITS_SZIND_SHIFT);
|
||||||
assert(szind <= NSIZES);
|
assert(szind <= SC_NSIZES);
|
||||||
return szind;
|
return szind;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline szind_t
|
static inline szind_t
|
||||||
extent_szind_get(const extent_t *extent) {
|
extent_szind_get(const extent_t *extent) {
|
||||||
szind_t szind = extent_szind_get_maybe_invalid(extent);
|
szind_t szind = extent_szind_get_maybe_invalid(extent);
|
||||||
assert(szind < NSIZES); /* Never call when "invalid". */
|
assert(szind < SC_NSIZES); /* Never call when "invalid". */
|
||||||
return szind;
|
return szind;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,6 +71,14 @@ extent_usize_get(const extent_t *extent) {
|
|||||||
return sz_index2size(extent_szind_get(extent));
|
return sz_index2size(extent_szind_get(extent));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline unsigned
|
||||||
|
extent_binshard_get(const extent_t *extent) {
|
||||||
|
unsigned binshard = (unsigned)((extent->e_bits &
|
||||||
|
EXTENT_BITS_BINSHARD_MASK) >> EXTENT_BITS_BINSHARD_SHIFT);
|
||||||
|
assert(binshard < bin_infos[extent_szind_get(extent)].n_shards);
|
||||||
|
return binshard;
|
||||||
|
}
|
||||||
|
|
||||||
static inline size_t
|
static inline size_t
|
||||||
extent_sn_get(const extent_t *extent) {
|
extent_sn_get(const extent_t *extent) {
|
||||||
return (size_t)((extent->e_bits & EXTENT_BITS_SN_MASK) >>
|
return (size_t)((extent->e_bits & EXTENT_BITS_SN_MASK) >>
|
||||||
@ -176,6 +186,11 @@ extent_prof_tctx_get(const extent_t *extent) {
|
|||||||
ATOMIC_ACQUIRE);
|
ATOMIC_ACQUIRE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline nstime_t
|
||||||
|
extent_prof_alloc_time_get(const extent_t *extent) {
|
||||||
|
return extent->e_alloc_time;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
extent_arena_set(extent_t *extent, arena_t *arena) {
|
extent_arena_set(extent_t *extent, arena_t *arena) {
|
||||||
unsigned arena_ind = (arena != NULL) ? arena_ind_get(arena) : ((1U <<
|
unsigned arena_ind = (arena != NULL) ? arena_ind_get(arena) : ((1U <<
|
||||||
@ -184,13 +199,21 @@ extent_arena_set(extent_t *extent, arena_t *arena) {
|
|||||||
((uint64_t)arena_ind << EXTENT_BITS_ARENA_SHIFT);
|
((uint64_t)arena_ind << EXTENT_BITS_ARENA_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
extent_binshard_set(extent_t *extent, unsigned binshard) {
|
||||||
|
/* The assertion assumes szind is set already. */
|
||||||
|
assert(binshard < bin_infos[extent_szind_get(extent)].n_shards);
|
||||||
|
extent->e_bits = (extent->e_bits & ~EXTENT_BITS_BINSHARD_MASK) |
|
||||||
|
((uint64_t)binshard << EXTENT_BITS_BINSHARD_SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
extent_addr_set(extent_t *extent, void *addr) {
|
extent_addr_set(extent_t *extent, void *addr) {
|
||||||
extent->e_addr = addr;
|
extent->e_addr = addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
extent_addr_randomize(UNUSED tsdn_t *tsdn, extent_t *extent, size_t alignment) {
|
extent_addr_randomize(tsdn_t *tsdn, extent_t *extent, size_t alignment) {
|
||||||
assert(extent_base_get(extent) == extent_addr_get(extent));
|
assert(extent_base_get(extent) == extent_addr_get(extent));
|
||||||
|
|
||||||
if (alignment < PAGE) {
|
if (alignment < PAGE) {
|
||||||
@ -234,7 +257,7 @@ extent_bsize_set(extent_t *extent, size_t bsize) {
|
|||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
extent_szind_set(extent_t *extent, szind_t szind) {
|
extent_szind_set(extent_t *extent, szind_t szind) {
|
||||||
assert(szind <= NSIZES); /* NSIZES means "invalid". */
|
assert(szind <= SC_NSIZES); /* SC_NSIZES means "invalid". */
|
||||||
extent->e_bits = (extent->e_bits & ~EXTENT_BITS_SZIND_MASK) |
|
extent->e_bits = (extent->e_bits & ~EXTENT_BITS_SZIND_MASK) |
|
||||||
((uint64_t)szind << EXTENT_BITS_SZIND_SHIFT);
|
((uint64_t)szind << EXTENT_BITS_SZIND_SHIFT);
|
||||||
}
|
}
|
||||||
@ -246,6 +269,16 @@ extent_nfree_set(extent_t *extent, unsigned nfree) {
|
|||||||
((uint64_t)nfree << EXTENT_BITS_NFREE_SHIFT);
|
((uint64_t)nfree << EXTENT_BITS_NFREE_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
extent_nfree_binshard_set(extent_t *extent, unsigned nfree, unsigned binshard) {
|
||||||
|
/* The assertion assumes szind is set already. */
|
||||||
|
assert(binshard < bin_infos[extent_szind_get(extent)].n_shards);
|
||||||
|
extent->e_bits = (extent->e_bits &
|
||||||
|
(~EXTENT_BITS_NFREE_MASK & ~EXTENT_BITS_BINSHARD_MASK)) |
|
||||||
|
((uint64_t)binshard << EXTENT_BITS_BINSHARD_SHIFT) |
|
||||||
|
((uint64_t)nfree << EXTENT_BITS_NFREE_SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
extent_nfree_inc(extent_t *extent) {
|
extent_nfree_inc(extent_t *extent) {
|
||||||
assert(extent_slab_get(extent));
|
assert(extent_slab_get(extent));
|
||||||
@ -258,6 +291,12 @@ extent_nfree_dec(extent_t *extent) {
|
|||||||
extent->e_bits -= ((uint64_t)1U << EXTENT_BITS_NFREE_SHIFT);
|
extent->e_bits -= ((uint64_t)1U << EXTENT_BITS_NFREE_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
extent_nfree_sub(extent_t *extent, uint64_t n) {
|
||||||
|
assert(extent_slab_get(extent));
|
||||||
|
extent->e_bits -= (n << EXTENT_BITS_NFREE_SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
extent_sn_set(extent_t *extent, size_t sn) {
|
extent_sn_set(extent_t *extent, size_t sn) {
|
||||||
extent->e_bits = (extent->e_bits & ~EXTENT_BITS_SN_MASK) |
|
extent->e_bits = (extent->e_bits & ~EXTENT_BITS_SN_MASK) |
|
||||||
@ -299,10 +338,35 @@ extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx) {
|
|||||||
atomic_store_p(&extent->e_prof_tctx, tctx, ATOMIC_RELEASE);
|
atomic_store_p(&extent->e_prof_tctx, tctx, ATOMIC_RELEASE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
extent_prof_alloc_time_set(extent_t *extent, nstime_t t) {
|
||||||
|
nstime_copy(&extent->e_alloc_time, &t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
extent_is_head_get(extent_t *extent) {
|
||||||
|
if (maps_coalesce) {
|
||||||
|
not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (bool)((extent->e_bits & EXTENT_BITS_IS_HEAD_MASK) >>
|
||||||
|
EXTENT_BITS_IS_HEAD_SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
extent_is_head_set(extent_t *extent, bool is_head) {
|
||||||
|
if (maps_coalesce) {
|
||||||
|
not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
extent->e_bits = (extent->e_bits & ~EXTENT_BITS_IS_HEAD_MASK) |
|
||||||
|
((uint64_t)is_head << EXTENT_BITS_IS_HEAD_SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size,
|
extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size,
|
||||||
bool slab, szind_t szind, size_t sn, extent_state_t state, bool zeroed,
|
bool slab, szind_t szind, size_t sn, extent_state_t state, bool zeroed,
|
||||||
bool committed, bool dumpable) {
|
bool committed, bool dumpable, extent_head_state_t is_head) {
|
||||||
assert(addr == PAGE_ADDR2BASE(addr) || !slab);
|
assert(addr == PAGE_ADDR2BASE(addr) || !slab);
|
||||||
|
|
||||||
extent_arena_set(extent, arena);
|
extent_arena_set(extent, arena);
|
||||||
@ -316,6 +380,10 @@ extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size,
|
|||||||
extent_committed_set(extent, committed);
|
extent_committed_set(extent, committed);
|
||||||
extent_dumpable_set(extent, dumpable);
|
extent_dumpable_set(extent, dumpable);
|
||||||
ql_elm_new(extent, ql_link);
|
ql_elm_new(extent, ql_link);
|
||||||
|
if (!maps_coalesce) {
|
||||||
|
extent_is_head_set(extent, (is_head == EXTENT_IS_HEAD) ? true :
|
||||||
|
false);
|
||||||
|
}
|
||||||
if (config_prof) {
|
if (config_prof) {
|
||||||
extent_prof_tctx_set(extent, NULL);
|
extent_prof_tctx_set(extent, NULL);
|
||||||
}
|
}
|
||||||
@ -327,7 +395,7 @@ extent_binit(extent_t *extent, void *addr, size_t bsize, size_t sn) {
|
|||||||
extent_addr_set(extent, addr);
|
extent_addr_set(extent, addr);
|
||||||
extent_bsize_set(extent, bsize);
|
extent_bsize_set(extent, bsize);
|
||||||
extent_slab_set(extent, false);
|
extent_slab_set(extent, false);
|
||||||
extent_szind_set(extent, NSIZES);
|
extent_szind_set(extent, SC_NSIZES);
|
||||||
extent_sn_set(extent, sn);
|
extent_sn_set(extent, sn);
|
||||||
extent_state_set(extent, extent_state_active);
|
extent_state_set(extent, extent_state_active);
|
||||||
extent_zeroed_set(extent, true);
|
extent_zeroed_set(extent, true);
|
||||||
|
@ -2,11 +2,12 @@
|
|||||||
#define JEMALLOC_INTERNAL_EXTENT_STRUCTS_H
|
#define JEMALLOC_INTERNAL_EXTENT_STRUCTS_H
|
||||||
|
|
||||||
#include "jemalloc/internal/atomic.h"
|
#include "jemalloc/internal/atomic.h"
|
||||||
|
#include "jemalloc/internal/bit_util.h"
|
||||||
#include "jemalloc/internal/bitmap.h"
|
#include "jemalloc/internal/bitmap.h"
|
||||||
#include "jemalloc/internal/mutex.h"
|
#include "jemalloc/internal/mutex.h"
|
||||||
#include "jemalloc/internal/ql.h"
|
#include "jemalloc/internal/ql.h"
|
||||||
#include "jemalloc/internal/ph.h"
|
#include "jemalloc/internal/ph.h"
|
||||||
#include "jemalloc/internal/size_classes.h"
|
#include "jemalloc/internal/sc.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
extent_state_active = 0,
|
extent_state_active = 0,
|
||||||
@ -28,9 +29,10 @@ struct extent_s {
|
|||||||
* t: state
|
* t: state
|
||||||
* i: szind
|
* i: szind
|
||||||
* f: nfree
|
* f: nfree
|
||||||
|
* s: bin_shard
|
||||||
* n: sn
|
* n: sn
|
||||||
*
|
*
|
||||||
* nnnnnnnn ... nnnnffff ffffffii iiiiiitt zdcbaaaa aaaaaaaa
|
* nnnnnnnn ... nnnnnnss ssssffff ffffffii iiiiiitt zdcbaaaa aaaaaaaa
|
||||||
*
|
*
|
||||||
* arena_ind: Arena from which this extent came, or all 1 bits if
|
* arena_ind: Arena from which this extent came, or all 1 bits if
|
||||||
* unassociated.
|
* unassociated.
|
||||||
@ -75,6 +77,8 @@ struct extent_s {
|
|||||||
*
|
*
|
||||||
* nfree: Number of free regions in slab.
|
* nfree: Number of free regions in slab.
|
||||||
*
|
*
|
||||||
|
* bin_shard: the shard of the bin from which this extent came.
|
||||||
|
*
|
||||||
* sn: Serial number (potentially non-unique).
|
* sn: Serial number (potentially non-unique).
|
||||||
*
|
*
|
||||||
* Serial numbers may wrap around if !opt_retain, but as long as
|
* Serial numbers may wrap around if !opt_retain, but as long as
|
||||||
@ -112,7 +116,7 @@ struct extent_s {
|
|||||||
#define EXTENT_BITS_STATE_SHIFT (EXTENT_BITS_ZEROED_WIDTH + EXTENT_BITS_ZEROED_SHIFT)
|
#define EXTENT_BITS_STATE_SHIFT (EXTENT_BITS_ZEROED_WIDTH + EXTENT_BITS_ZEROED_SHIFT)
|
||||||
#define EXTENT_BITS_STATE_MASK MASK(EXTENT_BITS_STATE_WIDTH, EXTENT_BITS_STATE_SHIFT)
|
#define EXTENT_BITS_STATE_MASK MASK(EXTENT_BITS_STATE_WIDTH, EXTENT_BITS_STATE_SHIFT)
|
||||||
|
|
||||||
#define EXTENT_BITS_SZIND_WIDTH LG_CEIL_NSIZES
|
#define EXTENT_BITS_SZIND_WIDTH LG_CEIL(SC_NSIZES)
|
||||||
#define EXTENT_BITS_SZIND_SHIFT (EXTENT_BITS_STATE_WIDTH + EXTENT_BITS_STATE_SHIFT)
|
#define EXTENT_BITS_SZIND_SHIFT (EXTENT_BITS_STATE_WIDTH + EXTENT_BITS_STATE_SHIFT)
|
||||||
#define EXTENT_BITS_SZIND_MASK MASK(EXTENT_BITS_SZIND_WIDTH, EXTENT_BITS_SZIND_SHIFT)
|
#define EXTENT_BITS_SZIND_MASK MASK(EXTENT_BITS_SZIND_WIDTH, EXTENT_BITS_SZIND_SHIFT)
|
||||||
|
|
||||||
@ -120,7 +124,15 @@ struct extent_s {
|
|||||||
#define EXTENT_BITS_NFREE_SHIFT (EXTENT_BITS_SZIND_WIDTH + EXTENT_BITS_SZIND_SHIFT)
|
#define EXTENT_BITS_NFREE_SHIFT (EXTENT_BITS_SZIND_WIDTH + EXTENT_BITS_SZIND_SHIFT)
|
||||||
#define EXTENT_BITS_NFREE_MASK MASK(EXTENT_BITS_NFREE_WIDTH, EXTENT_BITS_NFREE_SHIFT)
|
#define EXTENT_BITS_NFREE_MASK MASK(EXTENT_BITS_NFREE_WIDTH, EXTENT_BITS_NFREE_SHIFT)
|
||||||
|
|
||||||
#define EXTENT_BITS_SN_SHIFT (EXTENT_BITS_NFREE_WIDTH + EXTENT_BITS_NFREE_SHIFT)
|
#define EXTENT_BITS_BINSHARD_WIDTH 6
|
||||||
|
#define EXTENT_BITS_BINSHARD_SHIFT (EXTENT_BITS_NFREE_WIDTH + EXTENT_BITS_NFREE_SHIFT)
|
||||||
|
#define EXTENT_BITS_BINSHARD_MASK MASK(EXTENT_BITS_BINSHARD_WIDTH, EXTENT_BITS_BINSHARD_SHIFT)
|
||||||
|
|
||||||
|
#define EXTENT_BITS_IS_HEAD_WIDTH 1
|
||||||
|
#define EXTENT_BITS_IS_HEAD_SHIFT (EXTENT_BITS_BINSHARD_WIDTH + EXTENT_BITS_BINSHARD_SHIFT)
|
||||||
|
#define EXTENT_BITS_IS_HEAD_MASK MASK(EXTENT_BITS_IS_HEAD_WIDTH, EXTENT_BITS_IS_HEAD_SHIFT)
|
||||||
|
|
||||||
|
#define EXTENT_BITS_SN_SHIFT (EXTENT_BITS_IS_HEAD_WIDTH + EXTENT_BITS_IS_HEAD_SHIFT)
|
||||||
#define EXTENT_BITS_SN_MASK (UINT64_MAX << EXTENT_BITS_SN_SHIFT)
|
#define EXTENT_BITS_SN_MASK (UINT64_MAX << EXTENT_BITS_SN_SHIFT)
|
||||||
|
|
||||||
/* Pointer to the extent that this structure is responsible for. */
|
/* Pointer to the extent that this structure is responsible for. */
|
||||||
@ -160,13 +172,15 @@ struct extent_s {
|
|||||||
/* Small region slab metadata. */
|
/* Small region slab metadata. */
|
||||||
arena_slab_data_t e_slab_data;
|
arena_slab_data_t e_slab_data;
|
||||||
|
|
||||||
/*
|
/* Profiling data, used for large objects. */
|
||||||
* Profile counters, used for large objects. Points to a
|
struct {
|
||||||
* prof_tctx_t.
|
/* Time when this was allocated. */
|
||||||
*/
|
nstime_t e_alloc_time;
|
||||||
|
/* Points to a prof_tctx_t. */
|
||||||
atomic_p_t e_prof_tctx;
|
atomic_p_t e_prof_tctx;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
};
|
||||||
typedef ql_head(extent_t) extent_list_t;
|
typedef ql_head(extent_t) extent_list_t;
|
||||||
typedef ph(extent_t) extent_tree_t;
|
typedef ph(extent_t) extent_tree_t;
|
||||||
typedef ph(extent_t) extent_heap_t;
|
typedef ph(extent_t) extent_heap_t;
|
||||||
@ -180,14 +194,16 @@ struct extents_s {
|
|||||||
*
|
*
|
||||||
* Synchronization: mtx.
|
* Synchronization: mtx.
|
||||||
*/
|
*/
|
||||||
extent_heap_t heaps[NPSIZES+1];
|
extent_heap_t heaps[SC_NPSIZES + 1];
|
||||||
|
atomic_zu_t nextents[SC_NPSIZES + 1];
|
||||||
|
atomic_zu_t nbytes[SC_NPSIZES + 1];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bitmap for which set bits correspond to non-empty heaps.
|
* Bitmap for which set bits correspond to non-empty heaps.
|
||||||
*
|
*
|
||||||
* Synchronization: mtx.
|
* Synchronization: mtx.
|
||||||
*/
|
*/
|
||||||
bitmap_t bitmap[BITMAP_GROUPS(NPSIZES+1)];
|
bitmap_t bitmap[BITMAP_GROUPS(SC_NPSIZES + 1)];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* LRU of all extents in heaps.
|
* LRU of all extents in heaps.
|
||||||
@ -216,4 +232,25 @@ struct extents_s {
|
|||||||
bool delay_coalesce;
|
bool delay_coalesce;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following two structs are for experimental purposes. See
|
||||||
|
* experimental_utilization_query_ctl and
|
||||||
|
* experimental_utilization_batch_query_ctl in src/ctl.c.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct extent_util_stats_s {
|
||||||
|
size_t nfree;
|
||||||
|
size_t nregs;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct extent_util_stats_verbose_s {
|
||||||
|
void *slabcur_addr;
|
||||||
|
size_t nfree;
|
||||||
|
size_t nregs;
|
||||||
|
size_t size;
|
||||||
|
size_t bin_nfree;
|
||||||
|
size_t bin_nregs;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_EXTENT_STRUCTS_H */
|
#endif /* JEMALLOC_INTERNAL_EXTENT_STRUCTS_H */
|
||||||
|
@ -4,9 +4,10 @@
|
|||||||
typedef struct extent_s extent_t;
|
typedef struct extent_s extent_t;
|
||||||
typedef struct extents_s extents_t;
|
typedef struct extents_s extents_t;
|
||||||
|
|
||||||
#define EXTENT_HOOKS_INITIALIZER NULL
|
typedef struct extent_util_stats_s extent_util_stats_t;
|
||||||
|
typedef struct extent_util_stats_verbose_s extent_util_stats_verbose_t;
|
||||||
|
|
||||||
#define EXTENT_GROW_MAX_PIND (NPSIZES - 1)
|
#define EXTENT_HOOKS_INITIALIZER NULL
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When reuse (and split) an active extent, (1U << opt_lg_extent_max_active_fit)
|
* When reuse (and split) an active extent, (1U << opt_lg_extent_max_active_fit)
|
||||||
@ -14,4 +15,9 @@ typedef struct extents_s extents_t;
|
|||||||
*/
|
*/
|
||||||
#define LG_EXTENT_MAX_ACTIVE_FIT_DEFAULT 6
|
#define LG_EXTENT_MAX_ACTIVE_FIT_DEFAULT 6
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EXTENT_NOT_HEAD,
|
||||||
|
EXTENT_IS_HEAD /* Only relevant for Windows && opt.retain. */
|
||||||
|
} extent_head_state_t;
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_EXTENT_TYPES_H */
|
#endif /* JEMALLOC_INTERNAL_EXTENT_TYPES_H */
|
||||||
|
65
deps/jemalloc/include/jemalloc/internal/hash.h
vendored
65
deps/jemalloc/include/jemalloc/internal/hash.h
vendored
@ -104,8 +104,8 @@ hash_x86_32(const void *key, int len, uint32_t seed) {
|
|||||||
uint32_t k1 = 0;
|
uint32_t k1 = 0;
|
||||||
|
|
||||||
switch (len & 3) {
|
switch (len & 3) {
|
||||||
case 3: k1 ^= tail[2] << 16;
|
case 3: k1 ^= tail[2] << 16; JEMALLOC_FALLTHROUGH
|
||||||
case 2: k1 ^= tail[1] << 8;
|
case 2: k1 ^= tail[1] << 8; JEMALLOC_FALLTHROUGH
|
||||||
case 1: k1 ^= tail[0]; k1 *= c1; k1 = hash_rotl_32(k1, 15);
|
case 1: k1 ^= tail[0]; k1 *= c1; k1 = hash_rotl_32(k1, 15);
|
||||||
k1 *= c2; h1 ^= k1;
|
k1 *= c2; h1 ^= k1;
|
||||||
}
|
}
|
||||||
@ -119,7 +119,7 @@ hash_x86_32(const void *key, int len, uint32_t seed) {
|
|||||||
return h1;
|
return h1;
|
||||||
}
|
}
|
||||||
|
|
||||||
UNUSED static inline void
|
static inline void
|
||||||
hash_x86_128(const void *key, const int len, uint32_t seed,
|
hash_x86_128(const void *key, const int len, uint32_t seed,
|
||||||
uint64_t r_out[2]) {
|
uint64_t r_out[2]) {
|
||||||
const uint8_t * data = (const uint8_t *) key;
|
const uint8_t * data = (const uint8_t *) key;
|
||||||
@ -177,28 +177,29 @@ hash_x86_128(const void *key, const int len, uint32_t seed,
|
|||||||
uint32_t k4 = 0;
|
uint32_t k4 = 0;
|
||||||
|
|
||||||
switch (len & 15) {
|
switch (len & 15) {
|
||||||
case 15: k4 ^= tail[14] << 16;
|
case 15: k4 ^= tail[14] << 16; JEMALLOC_FALLTHROUGH
|
||||||
case 14: k4 ^= tail[13] << 8;
|
case 14: k4 ^= tail[13] << 8; JEMALLOC_FALLTHROUGH
|
||||||
case 13: k4 ^= tail[12] << 0;
|
case 13: k4 ^= tail[12] << 0;
|
||||||
k4 *= c4; k4 = hash_rotl_32(k4, 18); k4 *= c1; h4 ^= k4;
|
k4 *= c4; k4 = hash_rotl_32(k4, 18); k4 *= c1; h4 ^= k4;
|
||||||
|
JEMALLOC_FALLTHROUGH
|
||||||
case 12: k3 ^= tail[11] << 24;
|
case 12: k3 ^= tail[11] << 24; JEMALLOC_FALLTHROUGH
|
||||||
case 11: k3 ^= tail[10] << 16;
|
case 11: k3 ^= tail[10] << 16; JEMALLOC_FALLTHROUGH
|
||||||
case 10: k3 ^= tail[ 9] << 8;
|
case 10: k3 ^= tail[ 9] << 8; JEMALLOC_FALLTHROUGH
|
||||||
case 9: k3 ^= tail[ 8] << 0;
|
case 9: k3 ^= tail[ 8] << 0;
|
||||||
k3 *= c3; k3 = hash_rotl_32(k3, 17); k3 *= c4; h3 ^= k3;
|
k3 *= c3; k3 = hash_rotl_32(k3, 17); k3 *= c4; h3 ^= k3;
|
||||||
|
JEMALLOC_FALLTHROUGH
|
||||||
case 8: k2 ^= tail[ 7] << 24;
|
case 8: k2 ^= tail[ 7] << 24; JEMALLOC_FALLTHROUGH
|
||||||
case 7: k2 ^= tail[ 6] << 16;
|
case 7: k2 ^= tail[ 6] << 16; JEMALLOC_FALLTHROUGH
|
||||||
case 6: k2 ^= tail[ 5] << 8;
|
case 6: k2 ^= tail[ 5] << 8; JEMALLOC_FALLTHROUGH
|
||||||
case 5: k2 ^= tail[ 4] << 0;
|
case 5: k2 ^= tail[ 4] << 0;
|
||||||
k2 *= c2; k2 = hash_rotl_32(k2, 16); k2 *= c3; h2 ^= k2;
|
k2 *= c2; k2 = hash_rotl_32(k2, 16); k2 *= c3; h2 ^= k2;
|
||||||
|
JEMALLOC_FALLTHROUGH
|
||||||
case 4: k1 ^= tail[ 3] << 24;
|
case 4: k1 ^= tail[ 3] << 24; JEMALLOC_FALLTHROUGH
|
||||||
case 3: k1 ^= tail[ 2] << 16;
|
case 3: k1 ^= tail[ 2] << 16; JEMALLOC_FALLTHROUGH
|
||||||
case 2: k1 ^= tail[ 1] << 8;
|
case 2: k1 ^= tail[ 1] << 8; JEMALLOC_FALLTHROUGH
|
||||||
case 1: k1 ^= tail[ 0] << 0;
|
case 1: k1 ^= tail[ 0] << 0;
|
||||||
k1 *= c1; k1 = hash_rotl_32(k1, 15); k1 *= c2; h1 ^= k1;
|
k1 *= c1; k1 = hash_rotl_32(k1, 15); k1 *= c2; h1 ^= k1;
|
||||||
|
JEMALLOC_FALLTHROUGH
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +221,7 @@ hash_x86_128(const void *key, const int len, uint32_t seed,
|
|||||||
r_out[1] = (((uint64_t) h4) << 32) | h3;
|
r_out[1] = (((uint64_t) h4) << 32) | h3;
|
||||||
}
|
}
|
||||||
|
|
||||||
UNUSED static inline void
|
static inline void
|
||||||
hash_x64_128(const void *key, const int len, const uint32_t seed,
|
hash_x64_128(const void *key, const int len, const uint32_t seed,
|
||||||
uint64_t r_out[2]) {
|
uint64_t r_out[2]) {
|
||||||
const uint8_t *data = (const uint8_t *) key;
|
const uint8_t *data = (const uint8_t *) key;
|
||||||
@ -260,22 +261,22 @@ hash_x64_128(const void *key, const int len, const uint32_t seed,
|
|||||||
uint64_t k2 = 0;
|
uint64_t k2 = 0;
|
||||||
|
|
||||||
switch (len & 15) {
|
switch (len & 15) {
|
||||||
case 15: k2 ^= ((uint64_t)(tail[14])) << 48; /* falls through */
|
case 15: k2 ^= ((uint64_t)(tail[14])) << 48; JEMALLOC_FALLTHROUGH
|
||||||
case 14: k2 ^= ((uint64_t)(tail[13])) << 40; /* falls through */
|
case 14: k2 ^= ((uint64_t)(tail[13])) << 40; JEMALLOC_FALLTHROUGH
|
||||||
case 13: k2 ^= ((uint64_t)(tail[12])) << 32; /* falls through */
|
case 13: k2 ^= ((uint64_t)(tail[12])) << 32; JEMALLOC_FALLTHROUGH
|
||||||
case 12: k2 ^= ((uint64_t)(tail[11])) << 24; /* falls through */
|
case 12: k2 ^= ((uint64_t)(tail[11])) << 24; JEMALLOC_FALLTHROUGH
|
||||||
case 11: k2 ^= ((uint64_t)(tail[10])) << 16; /* falls through */
|
case 11: k2 ^= ((uint64_t)(tail[10])) << 16; JEMALLOC_FALLTHROUGH
|
||||||
case 10: k2 ^= ((uint64_t)(tail[ 9])) << 8; /* falls through */
|
case 10: k2 ^= ((uint64_t)(tail[ 9])) << 8; JEMALLOC_FALLTHROUGH
|
||||||
case 9: k2 ^= ((uint64_t)(tail[ 8])) << 0;
|
case 9: k2 ^= ((uint64_t)(tail[ 8])) << 0;
|
||||||
k2 *= c2; k2 = hash_rotl_64(k2, 33); k2 *= c1; h2 ^= k2;
|
k2 *= c2; k2 = hash_rotl_64(k2, 33); k2 *= c1; h2 ^= k2;
|
||||||
/* falls through */
|
JEMALLOC_FALLTHROUGH
|
||||||
case 8: k1 ^= ((uint64_t)(tail[ 7])) << 56; /* falls through */
|
case 8: k1 ^= ((uint64_t)(tail[ 7])) << 56; JEMALLOC_FALLTHROUGH
|
||||||
case 7: k1 ^= ((uint64_t)(tail[ 6])) << 48; /* falls through */
|
case 7: k1 ^= ((uint64_t)(tail[ 6])) << 48; JEMALLOC_FALLTHROUGH
|
||||||
case 6: k1 ^= ((uint64_t)(tail[ 5])) << 40; /* falls through */
|
case 6: k1 ^= ((uint64_t)(tail[ 5])) << 40; JEMALLOC_FALLTHROUGH
|
||||||
case 5: k1 ^= ((uint64_t)(tail[ 4])) << 32; /* falls through */
|
case 5: k1 ^= ((uint64_t)(tail[ 4])) << 32; JEMALLOC_FALLTHROUGH
|
||||||
case 4: k1 ^= ((uint64_t)(tail[ 3])) << 24; /* falls through */
|
case 4: k1 ^= ((uint64_t)(tail[ 3])) << 24; JEMALLOC_FALLTHROUGH
|
||||||
case 3: k1 ^= ((uint64_t)(tail[ 2])) << 16; /* falls through */
|
case 3: k1 ^= ((uint64_t)(tail[ 2])) << 16; JEMALLOC_FALLTHROUGH
|
||||||
case 2: k1 ^= ((uint64_t)(tail[ 1])) << 8; /* falls through */
|
case 2: k1 ^= ((uint64_t)(tail[ 1])) << 8; JEMALLOC_FALLTHROUGH
|
||||||
case 1: k1 ^= ((uint64_t)(tail[ 0])) << 0;
|
case 1: k1 ^= ((uint64_t)(tail[ 0])) << 0;
|
||||||
k1 *= c1; k1 = hash_rotl_64(k1, 31); k1 *= c2; h1 ^= k1;
|
k1 *= c1; k1 = hash_rotl_64(k1, 31); k1 *= c2; h1 ^= k1;
|
||||||
}
|
}
|
||||||
|
163
deps/jemalloc/include/jemalloc/internal/hook.h
vendored
Normal file
163
deps/jemalloc/include/jemalloc/internal/hook.h
vendored
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
#ifndef JEMALLOC_INTERNAL_HOOK_H
|
||||||
|
#define JEMALLOC_INTERNAL_HOOK_H
|
||||||
|
|
||||||
|
#include "jemalloc/internal/tsd.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This API is *extremely* experimental, and may get ripped out, changed in API-
|
||||||
|
* and ABI-incompatible ways, be insufficiently or incorrectly documented, etc.
|
||||||
|
*
|
||||||
|
* It allows hooking the stateful parts of the API to see changes as they
|
||||||
|
* happen.
|
||||||
|
*
|
||||||
|
* Allocation hooks are called after the allocation is done, free hooks are
|
||||||
|
* called before the free is done, and expand hooks are called after the
|
||||||
|
* allocation is expanded.
|
||||||
|
*
|
||||||
|
* For realloc and rallocx, if the expansion happens in place, the expansion
|
||||||
|
* hook is called. If it is moved, then the alloc hook is called on the new
|
||||||
|
* location, and then the free hook is called on the old location (i.e. both
|
||||||
|
* hooks are invoked in between the alloc and the dalloc).
|
||||||
|
*
|
||||||
|
* If we return NULL from OOM, then usize might not be trustworthy. Calling
|
||||||
|
* realloc(NULL, size) only calls the alloc hook, and calling realloc(ptr, 0)
|
||||||
|
* only calls the free hook. (Calling realloc(NULL, 0) is treated as malloc(0),
|
||||||
|
* and only calls the alloc hook).
|
||||||
|
*
|
||||||
|
* Reentrancy:
|
||||||
|
* Reentrancy is guarded against from within the hook implementation. If you
|
||||||
|
* call allocator functions from within a hook, the hooks will not be invoked
|
||||||
|
* again.
|
||||||
|
* Threading:
|
||||||
|
* The installation of a hook synchronizes with all its uses. If you can
|
||||||
|
* prove the installation of a hook happens-before a jemalloc entry point,
|
||||||
|
* then the hook will get invoked (unless there's a racing removal).
|
||||||
|
*
|
||||||
|
* Hook insertion appears to be atomic at a per-thread level (i.e. if a thread
|
||||||
|
* allocates and has the alloc hook invoked, then a subsequent free on the
|
||||||
|
* same thread will also have the free hook invoked).
|
||||||
|
*
|
||||||
|
* The *removal* of a hook does *not* block until all threads are done with
|
||||||
|
* the hook. Hook authors have to be resilient to this, and need some
|
||||||
|
* out-of-band mechanism for cleaning up any dynamically allocated memory
|
||||||
|
* associated with their hook.
|
||||||
|
* Ordering:
|
||||||
|
* Order of hook execution is unspecified, and may be different than insertion
|
||||||
|
* order.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define HOOK_MAX 4
|
||||||
|
|
||||||
|
enum hook_alloc_e {
|
||||||
|
hook_alloc_malloc,
|
||||||
|
hook_alloc_posix_memalign,
|
||||||
|
hook_alloc_aligned_alloc,
|
||||||
|
hook_alloc_calloc,
|
||||||
|
hook_alloc_memalign,
|
||||||
|
hook_alloc_valloc,
|
||||||
|
hook_alloc_mallocx,
|
||||||
|
|
||||||
|
/* The reallocating functions have both alloc and dalloc variants */
|
||||||
|
hook_alloc_realloc,
|
||||||
|
hook_alloc_rallocx,
|
||||||
|
};
|
||||||
|
/*
|
||||||
|
* We put the enum typedef after the enum, since this file may get included by
|
||||||
|
* jemalloc_cpp.cpp, and C++ disallows enum forward declarations.
|
||||||
|
*/
|
||||||
|
typedef enum hook_alloc_e hook_alloc_t;
|
||||||
|
|
||||||
|
enum hook_dalloc_e {
|
||||||
|
hook_dalloc_free,
|
||||||
|
hook_dalloc_dallocx,
|
||||||
|
hook_dalloc_sdallocx,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The dalloc halves of reallocation (not called if in-place expansion
|
||||||
|
* happens).
|
||||||
|
*/
|
||||||
|
hook_dalloc_realloc,
|
||||||
|
hook_dalloc_rallocx,
|
||||||
|
};
|
||||||
|
typedef enum hook_dalloc_e hook_dalloc_t;
|
||||||
|
|
||||||
|
|
||||||
|
enum hook_expand_e {
|
||||||
|
hook_expand_realloc,
|
||||||
|
hook_expand_rallocx,
|
||||||
|
hook_expand_xallocx,
|
||||||
|
};
|
||||||
|
typedef enum hook_expand_e hook_expand_t;
|
||||||
|
|
||||||
|
typedef void (*hook_alloc)(
|
||||||
|
void *extra, hook_alloc_t type, void *result, uintptr_t result_raw,
|
||||||
|
uintptr_t args_raw[3]);
|
||||||
|
|
||||||
|
typedef void (*hook_dalloc)(
|
||||||
|
void *extra, hook_dalloc_t type, void *address, uintptr_t args_raw[3]);
|
||||||
|
|
||||||
|
typedef void (*hook_expand)(
|
||||||
|
void *extra, hook_expand_t type, void *address, size_t old_usize,
|
||||||
|
size_t new_usize, uintptr_t result_raw, uintptr_t args_raw[4]);
|
||||||
|
|
||||||
|
typedef struct hooks_s hooks_t;
|
||||||
|
struct hooks_s {
|
||||||
|
hook_alloc alloc_hook;
|
||||||
|
hook_dalloc dalloc_hook;
|
||||||
|
hook_expand expand_hook;
|
||||||
|
void *extra;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Begin implementation details; everything above this point might one day live
|
||||||
|
* in a public API. Everything below this point never will.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The realloc pathways haven't gotten any refactoring love in a while, and it's
|
||||||
|
* fairly difficult to pass information from the entry point to the hooks. We
|
||||||
|
* put the informaiton the hooks will need into a struct to encapsulate
|
||||||
|
* everything.
|
||||||
|
*
|
||||||
|
* Much of these pathways are force-inlined, so that the compiler can avoid
|
||||||
|
* materializing this struct until we hit an extern arena function. For fairly
|
||||||
|
* goofy reasons, *many* of the realloc paths hit an extern arena function.
|
||||||
|
* These paths are cold enough that it doesn't matter; eventually, we should
|
||||||
|
* rewrite the realloc code to make the expand-in-place and the
|
||||||
|
* free-then-realloc paths more orthogonal, at which point we don't need to
|
||||||
|
* spread the hook logic all over the place.
|
||||||
|
*/
|
||||||
|
typedef struct hook_ralloc_args_s hook_ralloc_args_t;
|
||||||
|
struct hook_ralloc_args_s {
|
||||||
|
/* I.e. as opposed to rallocx. */
|
||||||
|
bool is_realloc;
|
||||||
|
/*
|
||||||
|
* The expand hook takes 4 arguments, even if only 3 are actually used;
|
||||||
|
* we add an extra one in case the user decides to memcpy without
|
||||||
|
* looking too closely at the hooked function.
|
||||||
|
*/
|
||||||
|
uintptr_t args[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns an opaque handle to be used when removing the hook. NULL means that
|
||||||
|
* we couldn't install the hook.
|
||||||
|
*/
|
||||||
|
bool hook_boot();
|
||||||
|
|
||||||
|
void *hook_install(tsdn_t *tsdn, hooks_t *hooks);
|
||||||
|
/* Uninstalls the hook with the handle previously returned from hook_install. */
|
||||||
|
void hook_remove(tsdn_t *tsdn, void *opaque);
|
||||||
|
|
||||||
|
/* Hooks */
|
||||||
|
|
||||||
|
void hook_invoke_alloc(hook_alloc_t type, void *result, uintptr_t result_raw,
|
||||||
|
uintptr_t args_raw[3]);
|
||||||
|
|
||||||
|
void hook_invoke_dalloc(hook_dalloc_t type, void *address,
|
||||||
|
uintptr_t args_raw[3]);
|
||||||
|
|
||||||
|
void hook_invoke_expand(hook_expand_t type, void *address, size_t old_usize,
|
||||||
|
size_t new_usize, uintptr_t result_raw, uintptr_t args_raw[4]);
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_INTERNAL_HOOK_H */
|
19
deps/jemalloc/include/jemalloc/internal/hooks.h
vendored
19
deps/jemalloc/include/jemalloc/internal/hooks.h
vendored
@ -1,19 +0,0 @@
|
|||||||
#ifndef JEMALLOC_INTERNAL_HOOKS_H
|
|
||||||
#define JEMALLOC_INTERNAL_HOOKS_H
|
|
||||||
|
|
||||||
extern JEMALLOC_EXPORT void (*hooks_arena_new_hook)();
|
|
||||||
extern JEMALLOC_EXPORT void (*hooks_libc_hook)();
|
|
||||||
|
|
||||||
#define JEMALLOC_HOOK(fn, hook) ((void)(hook != NULL && (hook(), 0)), fn)
|
|
||||||
|
|
||||||
#define open JEMALLOC_HOOK(open, hooks_libc_hook)
|
|
||||||
#define read JEMALLOC_HOOK(read, hooks_libc_hook)
|
|
||||||
#define write JEMALLOC_HOOK(write, hooks_libc_hook)
|
|
||||||
#define readlink JEMALLOC_HOOK(readlink, hooks_libc_hook)
|
|
||||||
#define close JEMALLOC_HOOK(close, hooks_libc_hook)
|
|
||||||
#define creat JEMALLOC_HOOK(creat, hooks_libc_hook)
|
|
||||||
#define secure_getenv JEMALLOC_HOOK(secure_getenv, hooks_libc_hook)
|
|
||||||
/* Note that this is undef'd and re-define'd in src/prof.c. */
|
|
||||||
#define _Unwind_Backtrace JEMALLOC_HOOK(_Unwind_Backtrace, hooks_libc_hook)
|
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_HOOKS_H */
|
|
@ -31,6 +31,9 @@
|
|||||||
# include <sys/uio.h>
|
# include <sys/uio.h>
|
||||||
# endif
|
# endif
|
||||||
# include <pthread.h>
|
# include <pthread.h>
|
||||||
|
# ifdef __FreeBSD__
|
||||||
|
# include <pthread_np.h>
|
||||||
|
# endif
|
||||||
# include <signal.h>
|
# include <signal.h>
|
||||||
# ifdef JEMALLOC_OS_UNFAIR_LOCK
|
# ifdef JEMALLOC_OS_UNFAIR_LOCK
|
||||||
# include <os/lock.h>
|
# include <os/lock.h>
|
||||||
|
@ -48,25 +48,13 @@
|
|||||||
|
|
||||||
/* Defined if GCC __atomic atomics are available. */
|
/* Defined if GCC __atomic atomics are available. */
|
||||||
#undef JEMALLOC_GCC_ATOMIC_ATOMICS
|
#undef JEMALLOC_GCC_ATOMIC_ATOMICS
|
||||||
|
/* and the 8-bit variant support. */
|
||||||
|
#undef JEMALLOC_GCC_U8_ATOMIC_ATOMICS
|
||||||
|
|
||||||
/* Defined if GCC __sync atomics are available. */
|
/* Defined if GCC __sync atomics are available. */
|
||||||
#undef JEMALLOC_GCC_SYNC_ATOMICS
|
#undef JEMALLOC_GCC_SYNC_ATOMICS
|
||||||
|
/* and the 8-bit variant support. */
|
||||||
/*
|
#undef JEMALLOC_GCC_U8_SYNC_ATOMICS
|
||||||
* Defined if __sync_add_and_fetch(uint32_t *, uint32_t) and
|
|
||||||
* __sync_sub_and_fetch(uint32_t *, uint32_t) are available, despite
|
|
||||||
* __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 not being defined (which means the
|
|
||||||
* functions are defined in libgcc instead of being inlines).
|
|
||||||
*/
|
|
||||||
#undef JE_FORCE_SYNC_COMPARE_AND_SWAP_4
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Defined if __sync_add_and_fetch(uint64_t *, uint64_t) and
|
|
||||||
* __sync_sub_and_fetch(uint64_t *, uint64_t) are available, despite
|
|
||||||
* __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 not being defined (which means the
|
|
||||||
* functions are defined in libgcc instead of being inlines).
|
|
||||||
*/
|
|
||||||
#undef JE_FORCE_SYNC_COMPARE_AND_SWAP_8
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Defined if __builtin_clz() and __builtin_clzl() are available.
|
* Defined if __builtin_clz() and __builtin_clzl() are available.
|
||||||
@ -78,12 +66,6 @@
|
|||||||
*/
|
*/
|
||||||
#undef JEMALLOC_OS_UNFAIR_LOCK
|
#undef JEMALLOC_OS_UNFAIR_LOCK
|
||||||
|
|
||||||
/*
|
|
||||||
* Defined if OSSpin*() functions are available, as provided by Darwin, and
|
|
||||||
* documented in the spinlock(3) manual page.
|
|
||||||
*/
|
|
||||||
#undef JEMALLOC_OSSPIN
|
|
||||||
|
|
||||||
/* Defined if syscall(2) is usable. */
|
/* Defined if syscall(2) is usable. */
|
||||||
#undef JEMALLOC_USE_SYSCALL
|
#undef JEMALLOC_USE_SYSCALL
|
||||||
|
|
||||||
@ -153,6 +135,9 @@
|
|||||||
/* JEMALLOC_STATS enables statistics calculation. */
|
/* JEMALLOC_STATS enables statistics calculation. */
|
||||||
#undef JEMALLOC_STATS
|
#undef JEMALLOC_STATS
|
||||||
|
|
||||||
|
/* JEMALLOC_EXPERIMENTAL_SMALLOCX_API enables experimental smallocx API. */
|
||||||
|
#undef JEMALLOC_EXPERIMENTAL_SMALLOCX_API
|
||||||
|
|
||||||
/* JEMALLOC_PROF enables allocation profiling. */
|
/* JEMALLOC_PROF enables allocation profiling. */
|
||||||
#undef JEMALLOC_PROF
|
#undef JEMALLOC_PROF
|
||||||
|
|
||||||
@ -233,6 +218,12 @@
|
|||||||
#undef JEMALLOC_INTERNAL_FFSL
|
#undef JEMALLOC_INTERNAL_FFSL
|
||||||
#undef JEMALLOC_INTERNAL_FFS
|
#undef JEMALLOC_INTERNAL_FFS
|
||||||
|
|
||||||
|
/*
|
||||||
|
* popcount*() functions to use for bitmapping.
|
||||||
|
*/
|
||||||
|
#undef JEMALLOC_INTERNAL_POPCOUNTL
|
||||||
|
#undef JEMALLOC_INTERNAL_POPCOUNT
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If defined, explicitly attempt to more uniformly distribute large allocation
|
* If defined, explicitly attempt to more uniformly distribute large allocation
|
||||||
* pointer alignments across all cache indices.
|
* pointer alignments across all cache indices.
|
||||||
@ -245,6 +236,12 @@
|
|||||||
*/
|
*/
|
||||||
#undef JEMALLOC_LOG
|
#undef JEMALLOC_LOG
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If defined, use readlinkat() (instead of readlink()) to follow
|
||||||
|
* /etc/malloc_conf.
|
||||||
|
*/
|
||||||
|
#undef JEMALLOC_READLINKAT
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Darwin (OS X) uses zones to work around Mach-O symbol override shortcomings.
|
* Darwin (OS X) uses zones to work around Mach-O symbol override shortcomings.
|
||||||
*/
|
*/
|
||||||
@ -363,4 +360,7 @@
|
|||||||
*/
|
*/
|
||||||
#undef JEMALLOC_STRERROR_R_RETURNS_CHAR_WITH_GNU_SOURCE
|
#undef JEMALLOC_STRERROR_R_RETURNS_CHAR_WITH_GNU_SOURCE
|
||||||
|
|
||||||
|
/* Performs additional safety checks when defined. */
|
||||||
|
#undef JEMALLOC_OPT_SAFETY_CHECKS
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_DEFS_H_ */
|
#endif /* JEMALLOC_INTERNAL_DEFS_H_ */
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#define JEMALLOC_INTERNAL_EXTERNS_H
|
#define JEMALLOC_INTERNAL_EXTERNS_H
|
||||||
|
|
||||||
#include "jemalloc/internal/atomic.h"
|
#include "jemalloc/internal/atomic.h"
|
||||||
#include "jemalloc/internal/size_classes.h"
|
|
||||||
#include "jemalloc/internal/tsd_types.h"
|
#include "jemalloc/internal/tsd_types.h"
|
||||||
|
|
||||||
/* TSD checks this to set thread local slow state accordingly. */
|
/* TSD checks this to set thread local slow state accordingly. */
|
||||||
@ -11,6 +10,7 @@ extern bool malloc_slow;
|
|||||||
/* Run-time options. */
|
/* Run-time options. */
|
||||||
extern bool opt_abort;
|
extern bool opt_abort;
|
||||||
extern bool opt_abort_conf;
|
extern bool opt_abort_conf;
|
||||||
|
extern bool opt_confirm_conf;
|
||||||
extern const char *opt_junk;
|
extern const char *opt_junk;
|
||||||
extern bool opt_junk_alloc;
|
extern bool opt_junk_alloc;
|
||||||
extern bool opt_junk_free;
|
extern bool opt_junk_free;
|
||||||
@ -25,6 +25,9 @@ extern unsigned ncpus;
|
|||||||
/* Number of arenas used for automatic multiplexing of threads and arenas. */
|
/* Number of arenas used for automatic multiplexing of threads and arenas. */
|
||||||
extern unsigned narenas_auto;
|
extern unsigned narenas_auto;
|
||||||
|
|
||||||
|
/* Base index for manual arenas. */
|
||||||
|
extern unsigned manual_arena_base;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Arenas that are used to service external requests. Not all elements of the
|
* Arenas that are used to service external requests. Not all elements of the
|
||||||
* arenas array are necessarily used; arenas are created lazily as needed.
|
* arenas array are necessarily used; arenas are created lazily as needed.
|
||||||
@ -49,5 +52,6 @@ void jemalloc_prefork(void);
|
|||||||
void jemalloc_postfork_parent(void);
|
void jemalloc_postfork_parent(void);
|
||||||
void jemalloc_postfork_child(void);
|
void jemalloc_postfork_child(void);
|
||||||
bool malloc_initialized(void);
|
bool malloc_initialized(void);
|
||||||
|
void je_sdallocx_noflags(void *ptr, size_t size);
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_EXTERNS_H */
|
#endif /* JEMALLOC_INTERNAL_EXTERNS_H */
|
||||||
|
@ -4,13 +4,15 @@
|
|||||||
#include "jemalloc/internal/atomic.h"
|
#include "jemalloc/internal/atomic.h"
|
||||||
#include "jemalloc/internal/bit_util.h"
|
#include "jemalloc/internal/bit_util.h"
|
||||||
#include "jemalloc/internal/jemalloc_internal_types.h"
|
#include "jemalloc/internal/jemalloc_internal_types.h"
|
||||||
#include "jemalloc/internal/size_classes.h"
|
#include "jemalloc/internal/sc.h"
|
||||||
#include "jemalloc/internal/ticker.h"
|
#include "jemalloc/internal/ticker.h"
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE malloc_cpuid_t
|
JEMALLOC_ALWAYS_INLINE malloc_cpuid_t
|
||||||
malloc_getcpu(void) {
|
malloc_getcpu(void) {
|
||||||
assert(have_percpu_arena);
|
assert(have_percpu_arena);
|
||||||
#if defined(JEMALLOC_HAVE_SCHED_GETCPU)
|
#if defined(_WIN32)
|
||||||
|
return GetCurrentProcessorNumber();
|
||||||
|
#elif defined(JEMALLOC_HAVE_SCHED_GETCPU)
|
||||||
return (malloc_cpuid_t)sched_getcpu();
|
return (malloc_cpuid_t)sched_getcpu();
|
||||||
#else
|
#else
|
||||||
not_reached();
|
not_reached();
|
||||||
@ -108,14 +110,14 @@ decay_ticker_get(tsd_t *tsd, unsigned ind) {
|
|||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE cache_bin_t *
|
JEMALLOC_ALWAYS_INLINE cache_bin_t *
|
||||||
tcache_small_bin_get(tcache_t *tcache, szind_t binind) {
|
tcache_small_bin_get(tcache_t *tcache, szind_t binind) {
|
||||||
assert(binind < NBINS);
|
assert(binind < SC_NBINS);
|
||||||
return &tcache->bins_small[binind];
|
return &tcache->bins_small[binind];
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE cache_bin_t *
|
JEMALLOC_ALWAYS_INLINE cache_bin_t *
|
||||||
tcache_large_bin_get(tcache_t *tcache, szind_t binind) {
|
tcache_large_bin_get(tcache_t *tcache, szind_t binind) {
|
||||||
assert(binind >= NBINS &&binind < nhbins);
|
assert(binind >= SC_NBINS &&binind < nhbins);
|
||||||
return &tcache->bins_large[binind - NBINS];
|
return &tcache->bins_large[binind - SC_NBINS];
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE bool
|
JEMALLOC_ALWAYS_INLINE bool
|
||||||
@ -156,7 +158,7 @@ pre_reentrancy(tsd_t *tsd, arena_t *arena) {
|
|||||||
if (fast) {
|
if (fast) {
|
||||||
/* Prepare slow path for reentrancy. */
|
/* Prepare slow path for reentrancy. */
|
||||||
tsd_slow_update(tsd);
|
tsd_slow_update(tsd);
|
||||||
assert(tsd->state == tsd_state_nominal_slow);
|
assert(tsd_state_get(tsd) == tsd_state_nominal_slow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +71,8 @@ arena_ichoose(tsd_t *tsd, arena_t *arena) {
|
|||||||
static inline bool
|
static inline bool
|
||||||
arena_is_auto(arena_t *arena) {
|
arena_is_auto(arena_t *arena) {
|
||||||
assert(narenas_auto > 0);
|
assert(narenas_auto > 0);
|
||||||
return (arena_ind_get(arena) < narenas_auto);
|
|
||||||
|
return (arena_ind_get(arena) < manual_arena_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE extent_t *
|
JEMALLOC_ALWAYS_INLINE extent_t *
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#ifndef JEMALLOC_INTERNAL_INLINES_C_H
|
#ifndef JEMALLOC_INTERNAL_INLINES_C_H
|
||||||
#define JEMALLOC_INTERNAL_INLINES_C_H
|
#define JEMALLOC_INTERNAL_INLINES_C_H
|
||||||
|
|
||||||
|
#include "jemalloc/internal/hook.h"
|
||||||
#include "jemalloc/internal/jemalloc_internal_types.h"
|
#include "jemalloc/internal/jemalloc_internal_types.h"
|
||||||
#include "jemalloc/internal/sz.h"
|
#include "jemalloc/internal/sz.h"
|
||||||
#include "jemalloc/internal/witness.h"
|
#include "jemalloc/internal/witness.h"
|
||||||
@ -42,7 +43,6 @@ iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, tcache_t *tcache,
|
|||||||
bool is_internal, arena_t *arena, bool slow_path) {
|
bool is_internal, arena_t *arena, bool slow_path) {
|
||||||
void *ret;
|
void *ret;
|
||||||
|
|
||||||
assert(size != 0);
|
|
||||||
assert(!is_internal || tcache == NULL);
|
assert(!is_internal || tcache == NULL);
|
||||||
assert(!is_internal || arena == NULL || arena_is_auto(arena));
|
assert(!is_internal || arena == NULL || arena_is_auto(arena));
|
||||||
if (!tsdn_null(tsdn) && tsd_reentrancy_level_get(tsdn_tsd(tsdn)) == 0) {
|
if (!tsdn_null(tsdn) && tsd_reentrancy_level_get(tsdn_tsd(tsdn)) == 0) {
|
||||||
@ -133,45 +133,47 @@ isdalloct(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
|
|||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void *
|
JEMALLOC_ALWAYS_INLINE void *
|
||||||
iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
|
iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
|
||||||
size_t extra, size_t alignment, bool zero, tcache_t *tcache,
|
size_t alignment, bool zero, tcache_t *tcache, arena_t *arena,
|
||||||
arena_t *arena) {
|
hook_ralloc_args_t *hook_args) {
|
||||||
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
||||||
WITNESS_RANK_CORE, 0);
|
WITNESS_RANK_CORE, 0);
|
||||||
void *p;
|
void *p;
|
||||||
size_t usize, copysize;
|
size_t usize, copysize;
|
||||||
|
|
||||||
usize = sz_sa2u(size + extra, alignment);
|
|
||||||
if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
p = ipalloct(tsdn, usize, alignment, zero, tcache, arena);
|
|
||||||
if (p == NULL) {
|
|
||||||
if (extra == 0) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
/* Try again, without extra this time. */
|
|
||||||
usize = sz_sa2u(size, alignment);
|
usize = sz_sa2u(size, alignment);
|
||||||
if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) {
|
if (unlikely(usize == 0 || usize > SC_LARGE_MAXCLASS)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
p = ipalloct(tsdn, usize, alignment, zero, tcache, arena);
|
p = ipalloct(tsdn, usize, alignment, zero, tcache, arena);
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
* Copy at most size bytes (not size+extra), since the caller has no
|
* Copy at most size bytes (not size+extra), since the caller has no
|
||||||
* expectation that the extra bytes will be reliably preserved.
|
* expectation that the extra bytes will be reliably preserved.
|
||||||
*/
|
*/
|
||||||
copysize = (size < oldsize) ? size : oldsize;
|
copysize = (size < oldsize) ? size : oldsize;
|
||||||
memcpy(p, ptr, copysize);
|
memcpy(p, ptr, copysize);
|
||||||
|
hook_invoke_alloc(hook_args->is_realloc
|
||||||
|
? hook_alloc_realloc : hook_alloc_rallocx, p, (uintptr_t)p,
|
||||||
|
hook_args->args);
|
||||||
|
hook_invoke_dalloc(hook_args->is_realloc
|
||||||
|
? hook_dalloc_realloc : hook_dalloc_rallocx, ptr, hook_args->args);
|
||||||
isdalloct(tsdn, ptr, oldsize, tcache, NULL, true);
|
isdalloct(tsdn, ptr, oldsize, tcache, NULL, true);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* is_realloc threads through the knowledge of whether or not this call comes
|
||||||
|
* from je_realloc (as opposed to je_rallocx); this ensures that we pass the
|
||||||
|
* correct entry point into any hooks.
|
||||||
|
* Note that these functions are all force-inlined, so no actual bool gets
|
||||||
|
* passed-around anywhere.
|
||||||
|
*/
|
||||||
JEMALLOC_ALWAYS_INLINE void *
|
JEMALLOC_ALWAYS_INLINE void *
|
||||||
iralloct(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t alignment,
|
iralloct(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t alignment,
|
||||||
bool zero, tcache_t *tcache, arena_t *arena) {
|
bool zero, tcache_t *tcache, arena_t *arena, hook_ralloc_args_t *hook_args)
|
||||||
|
{
|
||||||
assert(ptr != NULL);
|
assert(ptr != NULL);
|
||||||
assert(size != 0);
|
assert(size != 0);
|
||||||
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
||||||
@ -183,24 +185,24 @@ iralloct(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t alignment,
|
|||||||
* Existing object alignment is inadequate; allocate new space
|
* Existing object alignment is inadequate; allocate new space
|
||||||
* and copy.
|
* and copy.
|
||||||
*/
|
*/
|
||||||
return iralloct_realign(tsdn, ptr, oldsize, size, 0, alignment,
|
return iralloct_realign(tsdn, ptr, oldsize, size, alignment,
|
||||||
zero, tcache, arena);
|
zero, tcache, arena, hook_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
return arena_ralloc(tsdn, arena, ptr, oldsize, size, alignment, zero,
|
return arena_ralloc(tsdn, arena, ptr, oldsize, size, alignment, zero,
|
||||||
tcache);
|
tcache, hook_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void *
|
JEMALLOC_ALWAYS_INLINE void *
|
||||||
iralloc(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, size_t alignment,
|
iralloc(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, size_t alignment,
|
||||||
bool zero) {
|
bool zero, hook_ralloc_args_t *hook_args) {
|
||||||
return iralloct(tsd_tsdn(tsd), ptr, oldsize, size, alignment, zero,
|
return iralloct(tsd_tsdn(tsd), ptr, oldsize, size, alignment, zero,
|
||||||
tcache_get(tsd), NULL);
|
tcache_get(tsd), NULL, hook_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE bool
|
JEMALLOC_ALWAYS_INLINE bool
|
||||||
ixalloc(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra,
|
ixalloc(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra,
|
||||||
size_t alignment, bool zero) {
|
size_t alignment, bool zero, size_t *newsize) {
|
||||||
assert(ptr != NULL);
|
assert(ptr != NULL);
|
||||||
assert(size != 0);
|
assert(size != 0);
|
||||||
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
||||||
@ -209,10 +211,12 @@ ixalloc(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra,
|
|||||||
if (alignment != 0 && ((uintptr_t)ptr & ((uintptr_t)alignment-1))
|
if (alignment != 0 && ((uintptr_t)ptr & ((uintptr_t)alignment-1))
|
||||||
!= 0) {
|
!= 0) {
|
||||||
/* Existing object alignment is inadequate. */
|
/* Existing object alignment is inadequate. */
|
||||||
|
*newsize = oldsize;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return arena_ralloc_no_move(tsdn, ptr, oldsize, size, extra, zero);
|
return arena_ralloc_no_move(tsdn, ptr, oldsize, size, extra, zero,
|
||||||
|
newsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE int
|
JEMALLOC_ALWAYS_INLINE int
|
||||||
@ -228,7 +232,8 @@ iget_defrag_hint(tsdn_t *tsdn, void* ptr) {
|
|||||||
extent_t *slab = iealloc(tsdn, ptr);
|
extent_t *slab = iealloc(tsdn, ptr);
|
||||||
arena_t *arena = extent_arena_get(slab);
|
arena_t *arena = extent_arena_get(slab);
|
||||||
szind_t binind = extent_szind_get(slab);
|
szind_t binind = extent_szind_get(slab);
|
||||||
bin_t *bin = &arena->bins[binind];
|
unsigned binshard = extent_binshard_get(slab);
|
||||||
|
bin_t *bin = &arena->bins[binind].bin_shards[binshard];
|
||||||
malloc_mutex_lock(tsdn, &bin->lock);
|
malloc_mutex_lock(tsdn, &bin->lock);
|
||||||
/* don't bother moving allocations from the slab currently used for new allocations */
|
/* don't bother moving allocations from the slab currently used for new allocations */
|
||||||
if (slab != bin->slabcur) {
|
if (slab != bin->slabcur) {
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
# define restrict
|
# define restrict
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Various function pointers are statick and immutable except during testing. */
|
/* Various function pointers are static and immutable except during testing. */
|
||||||
#ifdef JEMALLOC_JET
|
#ifdef JEMALLOC_JET
|
||||||
# define JET_MUTABLE
|
# define JET_MUTABLE
|
||||||
#else
|
#else
|
||||||
@ -40,4 +40,75 @@
|
|||||||
#define JEMALLOC_VA_ARGS_HEAD(head, ...) head
|
#define JEMALLOC_VA_ARGS_HEAD(head, ...) head
|
||||||
#define JEMALLOC_VA_ARGS_TAIL(head, ...) __VA_ARGS__
|
#define JEMALLOC_VA_ARGS_TAIL(head, ...) __VA_ARGS__
|
||||||
|
|
||||||
|
#if (defined(__GNUC__) || defined(__GNUG__)) && !defined(__clang__) \
|
||||||
|
&& defined(JEMALLOC_HAVE_ATTR) && (__GNUC__ >= 7)
|
||||||
|
#define JEMALLOC_FALLTHROUGH JEMALLOC_ATTR(fallthrough);
|
||||||
|
#else
|
||||||
|
#define JEMALLOC_FALLTHROUGH /* falls through */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Diagnostic suppression macros */
|
||||||
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||||||
|
# define JEMALLOC_DIAGNOSTIC_PUSH __pragma(warning(push))
|
||||||
|
# define JEMALLOC_DIAGNOSTIC_POP __pragma(warning(pop))
|
||||||
|
# define JEMALLOC_DIAGNOSTIC_IGNORE(W) __pragma(warning(disable:W))
|
||||||
|
# define JEMALLOC_DIAGNOSTIC_IGNORE_MISSING_STRUCT_FIELD_INITIALIZERS
|
||||||
|
# define JEMALLOC_DIAGNOSTIC_IGNORE_TYPE_LIMITS
|
||||||
|
# define JEMALLOC_DIAGNOSTIC_IGNORE_ALLOC_SIZE_LARGER_THAN
|
||||||
|
# define JEMALLOC_DIAGNOSTIC_DISABLE_SPURIOUS
|
||||||
|
/* #pragma GCC diagnostic first appeared in gcc 4.6. */
|
||||||
|
#elif (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && \
|
||||||
|
(__GNUC_MINOR__ > 5)))) || defined(__clang__)
|
||||||
|
/*
|
||||||
|
* The JEMALLOC_PRAGMA__ macro is an implementation detail of the GCC and Clang
|
||||||
|
* diagnostic suppression macros and should not be used anywhere else.
|
||||||
|
*/
|
||||||
|
# define JEMALLOC_PRAGMA__(X) _Pragma(#X)
|
||||||
|
# define JEMALLOC_DIAGNOSTIC_PUSH JEMALLOC_PRAGMA__(GCC diagnostic push)
|
||||||
|
# define JEMALLOC_DIAGNOSTIC_POP JEMALLOC_PRAGMA__(GCC diagnostic pop)
|
||||||
|
# define JEMALLOC_DIAGNOSTIC_IGNORE(W) \
|
||||||
|
JEMALLOC_PRAGMA__(GCC diagnostic ignored W)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The -Wmissing-field-initializers warning is buggy in GCC versions < 5.1 and
|
||||||
|
* all clang versions up to version 7 (currently trunk, unreleased). This macro
|
||||||
|
* suppresses the warning for the affected compiler versions only.
|
||||||
|
*/
|
||||||
|
# if ((defined(__GNUC__) && !defined(__clang__)) && (__GNUC__ < 5)) || \
|
||||||
|
defined(__clang__)
|
||||||
|
# define JEMALLOC_DIAGNOSTIC_IGNORE_MISSING_STRUCT_FIELD_INITIALIZERS \
|
||||||
|
JEMALLOC_DIAGNOSTIC_IGNORE("-Wmissing-field-initializers")
|
||||||
|
# else
|
||||||
|
# define JEMALLOC_DIAGNOSTIC_IGNORE_MISSING_STRUCT_FIELD_INITIALIZERS
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# define JEMALLOC_DIAGNOSTIC_IGNORE_TYPE_LIMITS \
|
||||||
|
JEMALLOC_DIAGNOSTIC_IGNORE("-Wtype-limits")
|
||||||
|
# define JEMALLOC_DIAGNOSTIC_IGNORE_UNUSED_PARAMETER \
|
||||||
|
JEMALLOC_DIAGNOSTIC_IGNORE("-Wunused-parameter")
|
||||||
|
# if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 7)
|
||||||
|
# define JEMALLOC_DIAGNOSTIC_IGNORE_ALLOC_SIZE_LARGER_THAN \
|
||||||
|
JEMALLOC_DIAGNOSTIC_IGNORE("-Walloc-size-larger-than=")
|
||||||
|
# else
|
||||||
|
# define JEMALLOC_DIAGNOSTIC_IGNORE_ALLOC_SIZE_LARGER_THAN
|
||||||
|
# endif
|
||||||
|
# define JEMALLOC_DIAGNOSTIC_DISABLE_SPURIOUS \
|
||||||
|
JEMALLOC_DIAGNOSTIC_PUSH \
|
||||||
|
JEMALLOC_DIAGNOSTIC_IGNORE_UNUSED_PARAMETER
|
||||||
|
#else
|
||||||
|
# define JEMALLOC_DIAGNOSTIC_PUSH
|
||||||
|
# define JEMALLOC_DIAGNOSTIC_POP
|
||||||
|
# define JEMALLOC_DIAGNOSTIC_IGNORE(W)
|
||||||
|
# define JEMALLOC_DIAGNOSTIC_IGNORE_MISSING_STRUCT_FIELD_INITIALIZERS
|
||||||
|
# define JEMALLOC_DIAGNOSTIC_IGNORE_TYPE_LIMITS
|
||||||
|
# define JEMALLOC_DIAGNOSTIC_IGNORE_ALLOC_SIZE_LARGER_THAN
|
||||||
|
# define JEMALLOC_DIAGNOSTIC_DISABLE_SPURIOUS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disables spurious diagnostics for all headers. Since these headers are not
|
||||||
|
* included by users directly, it does not affect their diagnostic settings.
|
||||||
|
*/
|
||||||
|
JEMALLOC_DIAGNOSTIC_DISABLE_SPURIOUS
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_MACROS_H */
|
#endif /* JEMALLOC_INTERNAL_MACROS_H */
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#ifndef JEMALLOC_INTERNAL_TYPES_H
|
#ifndef JEMALLOC_INTERNAL_TYPES_H
|
||||||
#define JEMALLOC_INTERNAL_TYPES_H
|
#define JEMALLOC_INTERNAL_TYPES_H
|
||||||
|
|
||||||
|
#include "jemalloc/internal/quantum.h"
|
||||||
|
|
||||||
/* Page size index type. */
|
/* Page size index type. */
|
||||||
typedef unsigned pszind_t;
|
typedef unsigned pszind_t;
|
||||||
|
|
||||||
@ -50,79 +52,6 @@ typedef int malloc_cpuid_t;
|
|||||||
/* Smallest size class to support. */
|
/* Smallest size class to support. */
|
||||||
#define TINY_MIN (1U << LG_TINY_MIN)
|
#define TINY_MIN (1U << LG_TINY_MIN)
|
||||||
|
|
||||||
/*
|
|
||||||
* Minimum allocation alignment is 2^LG_QUANTUM bytes (ignoring tiny size
|
|
||||||
* classes).
|
|
||||||
*/
|
|
||||||
#ifndef LG_QUANTUM
|
|
||||||
# if (defined(__i386__) || defined(_M_IX86))
|
|
||||||
# define LG_QUANTUM 4
|
|
||||||
# endif
|
|
||||||
# ifdef __ia64__
|
|
||||||
# define LG_QUANTUM 4
|
|
||||||
# endif
|
|
||||||
# ifdef __alpha__
|
|
||||||
# define LG_QUANTUM 4
|
|
||||||
# endif
|
|
||||||
# if (defined(__sparc64__) || defined(__sparcv9) || defined(__sparc_v9__))
|
|
||||||
# define LG_QUANTUM 4
|
|
||||||
# endif
|
|
||||||
# if (defined(__amd64__) || defined(__x86_64__) || defined(_M_X64))
|
|
||||||
# define LG_QUANTUM 4
|
|
||||||
# endif
|
|
||||||
# ifdef __arm__
|
|
||||||
# define LG_QUANTUM 3
|
|
||||||
# endif
|
|
||||||
# ifdef __aarch64__
|
|
||||||
# define LG_QUANTUM 4
|
|
||||||
# endif
|
|
||||||
# ifdef __hppa__
|
|
||||||
# define LG_QUANTUM 4
|
|
||||||
# endif
|
|
||||||
# ifdef __m68k__
|
|
||||||
# define LG_QUANTUM 3
|
|
||||||
# endif
|
|
||||||
# ifdef __mips__
|
|
||||||
# define LG_QUANTUM 3
|
|
||||||
# endif
|
|
||||||
# ifdef __nios2__
|
|
||||||
# define LG_QUANTUM 3
|
|
||||||
# endif
|
|
||||||
# ifdef __or1k__
|
|
||||||
# define LG_QUANTUM 3
|
|
||||||
# endif
|
|
||||||
# ifdef __powerpc__
|
|
||||||
# define LG_QUANTUM 4
|
|
||||||
# endif
|
|
||||||
# if defined(__riscv) || defined(__riscv__)
|
|
||||||
# define LG_QUANTUM 4
|
|
||||||
# endif
|
|
||||||
# ifdef __s390__
|
|
||||||
# define LG_QUANTUM 4
|
|
||||||
# endif
|
|
||||||
# if (defined (__SH3E__) || defined(__SH4_SINGLE__) || defined(__SH4__) || \
|
|
||||||
defined(__SH4_SINGLE_ONLY__))
|
|
||||||
# define LG_QUANTUM 4
|
|
||||||
# endif
|
|
||||||
# ifdef __tile__
|
|
||||||
# define LG_QUANTUM 4
|
|
||||||
# endif
|
|
||||||
# ifdef __le32__
|
|
||||||
# define LG_QUANTUM 4
|
|
||||||
# endif
|
|
||||||
# ifndef LG_QUANTUM
|
|
||||||
# error "Unknown minimum alignment for architecture; specify via "
|
|
||||||
"--with-lg-quantum"
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define QUANTUM ((size_t)(1U << LG_QUANTUM))
|
|
||||||
#define QUANTUM_MASK (QUANTUM - 1)
|
|
||||||
|
|
||||||
/* Return the smallest quantum multiple that is >= a. */
|
|
||||||
#define QUANTUM_CEILING(a) \
|
|
||||||
(((a) + QUANTUM_MASK) & ~QUANTUM_MASK)
|
|
||||||
|
|
||||||
#define LONG ((size_t)(1U << LG_SIZEOF_LONG))
|
#define LONG ((size_t)(1U << LG_SIZEOF_LONG))
|
||||||
#define LONG_MASK (LONG - 1)
|
#define LONG_MASK (LONG - 1)
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
# include "../jemalloc@install_suffix@.h"
|
# include "../jemalloc@install_suffix@.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (defined(JEMALLOC_OSATOMIC) || defined(JEMALLOC_OSSPIN))
|
#if defined(JEMALLOC_OSATOMIC)
|
||||||
#include <libkern/OSAtomic.h>
|
#include <libkern/OSAtomic.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -45,7 +45,7 @@
|
|||||||
# include "jemalloc/internal/private_namespace_jet.h"
|
# include "jemalloc/internal/private_namespace_jet.h"
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
#include "jemalloc/internal/hooks.h"
|
#include "jemalloc/internal/test_hooks.h"
|
||||||
|
|
||||||
#ifdef JEMALLOC_DEFINE_MADVISE_FREE
|
#ifdef JEMALLOC_DEFINE_MADVISE_FREE
|
||||||
# define JEMALLOC_MADV_FREE 8
|
# define JEMALLOC_MADV_FREE 8
|
||||||
@ -161,7 +161,26 @@ static const bool config_log =
|
|||||||
false
|
false
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
#ifdef JEMALLOC_HAVE_SCHED_GETCPU
|
/*
|
||||||
|
* Are extra safety checks enabled; things like checking the size of sized
|
||||||
|
* deallocations, double-frees, etc.
|
||||||
|
*/
|
||||||
|
static const bool config_opt_safety_checks =
|
||||||
|
#ifdef JEMALLOC_OPT_SAFETY_CHECKS
|
||||||
|
true
|
||||||
|
#elif defined(JEMALLOC_DEBUG)
|
||||||
|
/*
|
||||||
|
* This lets us only guard safety checks by one flag instead of two; fast
|
||||||
|
* checks can guard solely by config_opt_safety_checks and run in debug mode
|
||||||
|
* too.
|
||||||
|
*/
|
||||||
|
true
|
||||||
|
#else
|
||||||
|
false
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(JEMALLOC_HAVE_SCHED_GETCPU)
|
||||||
/* Currently percpu_arena depends on sched_getcpu. */
|
/* Currently percpu_arena depends on sched_getcpu. */
|
||||||
#define JEMALLOC_PERCPU_ARENA
|
#define JEMALLOC_PERCPU_ARENA
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
#ifndef JEMALLOC_INTERNAL_LARGE_EXTERNS_H
|
#ifndef JEMALLOC_INTERNAL_LARGE_EXTERNS_H
|
||||||
#define JEMALLOC_INTERNAL_LARGE_EXTERNS_H
|
#define JEMALLOC_INTERNAL_LARGE_EXTERNS_H
|
||||||
|
|
||||||
|
#include "jemalloc/internal/hook.h"
|
||||||
|
|
||||||
void *large_malloc(tsdn_t *tsdn, arena_t *arena, size_t usize, bool zero);
|
void *large_malloc(tsdn_t *tsdn, arena_t *arena, size_t usize, bool zero);
|
||||||
void *large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment,
|
void *large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment,
|
||||||
bool zero);
|
bool zero);
|
||||||
bool large_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min,
|
bool large_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min,
|
||||||
size_t usize_max, bool zero);
|
size_t usize_max, bool zero);
|
||||||
void *large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize,
|
void *large_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t usize,
|
||||||
size_t alignment, bool zero, tcache_t *tcache);
|
size_t alignment, bool zero, tcache_t *tcache,
|
||||||
|
hook_ralloc_args_t *hook_args);
|
||||||
|
|
||||||
typedef void (large_dalloc_junk_t)(void *, size_t);
|
typedef void (large_dalloc_junk_t)(void *, size_t);
|
||||||
extern large_dalloc_junk_t *JET_MUTABLE large_dalloc_junk;
|
extern large_dalloc_junk_t *JET_MUTABLE large_dalloc_junk;
|
||||||
@ -23,4 +26,7 @@ prof_tctx_t *large_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent);
|
|||||||
void large_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, prof_tctx_t *tctx);
|
void large_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, prof_tctx_t *tctx);
|
||||||
void large_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent);
|
void large_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent);
|
||||||
|
|
||||||
|
nstime_t large_prof_alloc_time_get(const extent_t *extent);
|
||||||
|
void large_prof_alloc_time_set(extent_t *extent, nstime_t time);
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_LARGE_EXTERNS_H */
|
#endif /* JEMALLOC_INTERNAL_LARGE_EXTERNS_H */
|
||||||
|
@ -54,7 +54,7 @@ size_t malloc_vsnprintf(char *str, size_t size, const char *format,
|
|||||||
size_t malloc_snprintf(char *str, size_t size, const char *format, ...)
|
size_t malloc_snprintf(char *str, size_t size, const char *format, ...)
|
||||||
JEMALLOC_FORMAT_PRINTF(3, 4);
|
JEMALLOC_FORMAT_PRINTF(3, 4);
|
||||||
/*
|
/*
|
||||||
* The caller can set write_cb and cbopaque to null to choose to print with the
|
* The caller can set write_cb to null to choose to print with the
|
||||||
* je_malloc_message hook.
|
* je_malloc_message hook.
|
||||||
*/
|
*/
|
||||||
void malloc_vcprintf(void (*write_cb)(void *, const char *), void *cbopaque,
|
void malloc_vcprintf(void (*write_cb)(void *, const char *), void *cbopaque,
|
||||||
|
64
deps/jemalloc/include/jemalloc/internal/mutex.h
vendored
64
deps/jemalloc/include/jemalloc/internal/mutex.h
vendored
@ -37,14 +37,17 @@ struct malloc_mutex_s {
|
|||||||
# endif
|
# endif
|
||||||
#elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
|
#elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
|
||||||
os_unfair_lock lock;
|
os_unfair_lock lock;
|
||||||
#elif (defined(JEMALLOC_OSSPIN))
|
|
||||||
OSSpinLock lock;
|
|
||||||
#elif (defined(JEMALLOC_MUTEX_INIT_CB))
|
#elif (defined(JEMALLOC_MUTEX_INIT_CB))
|
||||||
pthread_mutex_t lock;
|
pthread_mutex_t lock;
|
||||||
malloc_mutex_t *postponed_next;
|
malloc_mutex_t *postponed_next;
|
||||||
#else
|
#else
|
||||||
pthread_mutex_t lock;
|
pthread_mutex_t lock;
|
||||||
#endif
|
#endif
|
||||||
|
/*
|
||||||
|
* Hint flag to avoid exclusive cache line contention
|
||||||
|
* during spin waiting
|
||||||
|
*/
|
||||||
|
atomic_b_t locked;
|
||||||
};
|
};
|
||||||
/*
|
/*
|
||||||
* We only touch witness when configured w/ debug. However we
|
* We only touch witness when configured w/ debug. However we
|
||||||
@ -84,10 +87,6 @@ struct malloc_mutex_s {
|
|||||||
# define MALLOC_MUTEX_LOCK(m) os_unfair_lock_lock(&(m)->lock)
|
# define MALLOC_MUTEX_LOCK(m) os_unfair_lock_lock(&(m)->lock)
|
||||||
# define MALLOC_MUTEX_UNLOCK(m) os_unfair_lock_unlock(&(m)->lock)
|
# define MALLOC_MUTEX_UNLOCK(m) os_unfair_lock_unlock(&(m)->lock)
|
||||||
# define MALLOC_MUTEX_TRYLOCK(m) (!os_unfair_lock_trylock(&(m)->lock))
|
# define MALLOC_MUTEX_TRYLOCK(m) (!os_unfair_lock_trylock(&(m)->lock))
|
||||||
#elif (defined(JEMALLOC_OSSPIN))
|
|
||||||
# define MALLOC_MUTEX_LOCK(m) OSSpinLockLock(&(m)->lock)
|
|
||||||
# define MALLOC_MUTEX_UNLOCK(m) OSSpinLockUnlock(&(m)->lock)
|
|
||||||
# define MALLOC_MUTEX_TRYLOCK(m) (!OSSpinLockTry(&(m)->lock))
|
|
||||||
#else
|
#else
|
||||||
# define MALLOC_MUTEX_LOCK(m) pthread_mutex_lock(&(m)->lock)
|
# define MALLOC_MUTEX_LOCK(m) pthread_mutex_lock(&(m)->lock)
|
||||||
# define MALLOC_MUTEX_UNLOCK(m) pthread_mutex_unlock(&(m)->lock)
|
# define MALLOC_MUTEX_UNLOCK(m) pthread_mutex_unlock(&(m)->lock)
|
||||||
@ -101,23 +100,38 @@ struct malloc_mutex_s {
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# define MALLOC_MUTEX_INITIALIZER
|
# define MALLOC_MUTEX_INITIALIZER
|
||||||
#elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
|
#elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
|
||||||
|
# if defined(JEMALLOC_DEBUG)
|
||||||
# define MALLOC_MUTEX_INITIALIZER \
|
# define MALLOC_MUTEX_INITIALIZER \
|
||||||
{{{LOCK_PROF_DATA_INITIALIZER, OS_UNFAIR_LOCK_INIT}}, \
|
{{{LOCK_PROF_DATA_INITIALIZER, OS_UNFAIR_LOCK_INIT, ATOMIC_INIT(false)}}, \
|
||||||
WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)}
|
WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT), 0}
|
||||||
#elif (defined(JEMALLOC_OSSPIN))
|
# else
|
||||||
# define MALLOC_MUTEX_INITIALIZER \
|
# define MALLOC_MUTEX_INITIALIZER \
|
||||||
{{{LOCK_PROF_DATA_INITIALIZER, 0}}, \
|
{{{LOCK_PROF_DATA_INITIALIZER, OS_UNFAIR_LOCK_INIT, ATOMIC_INIT(false)}}, \
|
||||||
WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)}
|
WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)}
|
||||||
|
# endif
|
||||||
#elif (defined(JEMALLOC_MUTEX_INIT_CB))
|
#elif (defined(JEMALLOC_MUTEX_INIT_CB))
|
||||||
|
# if (defined(JEMALLOC_DEBUG))
|
||||||
# define MALLOC_MUTEX_INITIALIZER \
|
# define MALLOC_MUTEX_INITIALIZER \
|
||||||
{{{LOCK_PROF_DATA_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, NULL}}, \
|
{{{LOCK_PROF_DATA_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, NULL, ATOMIC_INIT(false)}}, \
|
||||||
|
WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT), 0}
|
||||||
|
# else
|
||||||
|
# define MALLOC_MUTEX_INITIALIZER \
|
||||||
|
{{{LOCK_PROF_DATA_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, NULL, ATOMIC_INIT(false)}}, \
|
||||||
WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)}
|
WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)}
|
||||||
|
# endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
# define MALLOC_MUTEX_TYPE PTHREAD_MUTEX_DEFAULT
|
# define MALLOC_MUTEX_TYPE PTHREAD_MUTEX_DEFAULT
|
||||||
|
# if defined(JEMALLOC_DEBUG)
|
||||||
# define MALLOC_MUTEX_INITIALIZER \
|
# define MALLOC_MUTEX_INITIALIZER \
|
||||||
{{{LOCK_PROF_DATA_INITIALIZER, PTHREAD_MUTEX_INITIALIZER}}, \
|
{{{LOCK_PROF_DATA_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, ATOMIC_INIT(false)}}, \
|
||||||
|
WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT), 0}
|
||||||
|
# else
|
||||||
|
# define MALLOC_MUTEX_INITIALIZER \
|
||||||
|
{{{LOCK_PROF_DATA_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, ATOMIC_INIT(false)}}, \
|
||||||
WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)}
|
WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)}
|
||||||
# endif
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef JEMALLOC_LAZY_LOCK
|
#ifdef JEMALLOC_LAZY_LOCK
|
||||||
extern bool isthreaded;
|
extern bool isthreaded;
|
||||||
@ -139,6 +153,7 @@ void malloc_mutex_lock_slow(malloc_mutex_t *mutex);
|
|||||||
static inline void
|
static inline void
|
||||||
malloc_mutex_lock_final(malloc_mutex_t *mutex) {
|
malloc_mutex_lock_final(malloc_mutex_t *mutex) {
|
||||||
MALLOC_MUTEX_LOCK(mutex);
|
MALLOC_MUTEX_LOCK(mutex);
|
||||||
|
atomic_store_b(&mutex->locked, true, ATOMIC_RELAXED);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
@ -164,6 +179,7 @@ malloc_mutex_trylock(tsdn_t *tsdn, malloc_mutex_t *mutex) {
|
|||||||
witness_assert_not_owner(tsdn_witness_tsdp_get(tsdn), &mutex->witness);
|
witness_assert_not_owner(tsdn_witness_tsdp_get(tsdn), &mutex->witness);
|
||||||
if (isthreaded) {
|
if (isthreaded) {
|
||||||
if (malloc_mutex_trylock_final(mutex)) {
|
if (malloc_mutex_trylock_final(mutex)) {
|
||||||
|
atomic_store_b(&mutex->locked, true, ATOMIC_RELAXED);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
mutex_owner_stats_update(tsdn, mutex);
|
mutex_owner_stats_update(tsdn, mutex);
|
||||||
@ -203,6 +219,7 @@ malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) {
|
|||||||
if (isthreaded) {
|
if (isthreaded) {
|
||||||
if (malloc_mutex_trylock_final(mutex)) {
|
if (malloc_mutex_trylock_final(mutex)) {
|
||||||
malloc_mutex_lock_slow(mutex);
|
malloc_mutex_lock_slow(mutex);
|
||||||
|
atomic_store_b(&mutex->locked, true, ATOMIC_RELAXED);
|
||||||
}
|
}
|
||||||
mutex_owner_stats_update(tsdn, mutex);
|
mutex_owner_stats_update(tsdn, mutex);
|
||||||
}
|
}
|
||||||
@ -211,6 +228,7 @@ malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) {
|
|||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex) {
|
malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex) {
|
||||||
|
atomic_store_b(&mutex->locked, false, ATOMIC_RELAXED);
|
||||||
witness_unlock(tsdn_witness_tsdp_get(tsdn), &mutex->witness);
|
witness_unlock(tsdn_witness_tsdp_get(tsdn), &mutex->witness);
|
||||||
if (isthreaded) {
|
if (isthreaded) {
|
||||||
MALLOC_MUTEX_UNLOCK(mutex);
|
MALLOC_MUTEX_UNLOCK(mutex);
|
||||||
@ -245,4 +263,26 @@ malloc_mutex_prof_read(tsdn_t *tsdn, mutex_prof_data_t *data,
|
|||||||
atomic_store_u32(&data->n_waiting_thds, 0, ATOMIC_RELAXED);
|
atomic_store_u32(&data->n_waiting_thds, 0, ATOMIC_RELAXED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
malloc_mutex_prof_accum(tsdn_t *tsdn, mutex_prof_data_t *data,
|
||||||
|
malloc_mutex_t *mutex) {
|
||||||
|
mutex_prof_data_t *source = &mutex->prof_data;
|
||||||
|
/* Can only read holding the mutex. */
|
||||||
|
malloc_mutex_assert_owner(tsdn, mutex);
|
||||||
|
|
||||||
|
nstime_add(&data->tot_wait_time, &source->tot_wait_time);
|
||||||
|
if (nstime_compare(&source->max_wait_time, &data->max_wait_time) > 0) {
|
||||||
|
nstime_copy(&data->max_wait_time, &source->max_wait_time);
|
||||||
|
}
|
||||||
|
data->n_wait_times += source->n_wait_times;
|
||||||
|
data->n_spin_acquired += source->n_spin_acquired;
|
||||||
|
if (data->max_n_thds < source->max_n_thds) {
|
||||||
|
data->max_n_thds = source->max_n_thds;
|
||||||
|
}
|
||||||
|
/* n_wait_thds is not reported. */
|
||||||
|
atomic_store_u32(&data->n_waiting_thds, 0, ATOMIC_RELAXED);
|
||||||
|
data->n_owner_switches += source->n_owner_switches;
|
||||||
|
data->n_lock_ops += source->n_lock_ops;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_MUTEX_H */
|
#endif /* JEMALLOC_INTERNAL_MUTEX_H */
|
||||||
|
@ -35,22 +35,31 @@ typedef enum {
|
|||||||
mutex_prof_num_arena_mutexes
|
mutex_prof_num_arena_mutexes
|
||||||
} mutex_prof_arena_ind_t;
|
} mutex_prof_arena_ind_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The forth parameter is a boolean value that is true for derived rate counters
|
||||||
|
* and false for real ones.
|
||||||
|
*/
|
||||||
#define MUTEX_PROF_UINT64_COUNTERS \
|
#define MUTEX_PROF_UINT64_COUNTERS \
|
||||||
OP(num_ops, uint64_t, "n_lock_ops") \
|
OP(num_ops, uint64_t, "n_lock_ops", false, num_ops) \
|
||||||
OP(num_wait, uint64_t, "n_waiting") \
|
OP(num_ops_ps, uint64_t, "(#/sec)", true, num_ops) \
|
||||||
OP(num_spin_acq, uint64_t, "n_spin_acq") \
|
OP(num_wait, uint64_t, "n_waiting", false, num_wait) \
|
||||||
OP(num_owner_switch, uint64_t, "n_owner_switch") \
|
OP(num_wait_ps, uint64_t, "(#/sec)", true, num_wait) \
|
||||||
OP(total_wait_time, uint64_t, "total_wait_ns") \
|
OP(num_spin_acq, uint64_t, "n_spin_acq", false, num_spin_acq) \
|
||||||
OP(max_wait_time, uint64_t, "max_wait_ns")
|
OP(num_spin_acq_ps, uint64_t, "(#/sec)", true, num_spin_acq) \
|
||||||
|
OP(num_owner_switch, uint64_t, "n_owner_switch", false, num_owner_switch) \
|
||||||
|
OP(num_owner_switch_ps, uint64_t, "(#/sec)", true, num_owner_switch) \
|
||||||
|
OP(total_wait_time, uint64_t, "total_wait_ns", false, total_wait_time) \
|
||||||
|
OP(total_wait_time_ps, uint64_t, "(#/sec)", true, total_wait_time) \
|
||||||
|
OP(max_wait_time, uint64_t, "max_wait_ns", false, max_wait_time)
|
||||||
|
|
||||||
#define MUTEX_PROF_UINT32_COUNTERS \
|
#define MUTEX_PROF_UINT32_COUNTERS \
|
||||||
OP(max_num_thds, uint32_t, "max_n_thds")
|
OP(max_num_thds, uint32_t, "max_n_thds", false, max_num_thds)
|
||||||
|
|
||||||
#define MUTEX_PROF_COUNTERS \
|
#define MUTEX_PROF_COUNTERS \
|
||||||
MUTEX_PROF_UINT64_COUNTERS \
|
MUTEX_PROF_UINT64_COUNTERS \
|
||||||
MUTEX_PROF_UINT32_COUNTERS
|
MUTEX_PROF_UINT32_COUNTERS
|
||||||
|
|
||||||
#define OP(counter, type, human) mutex_counter_##counter,
|
#define OP(counter, type, human, derived, base_counter) mutex_counter_##counter,
|
||||||
|
|
||||||
#define COUNTER_ENUM(counter_list, t) \
|
#define COUNTER_ENUM(counter_list, t) \
|
||||||
typedef enum { \
|
typedef enum { \
|
||||||
|
@ -14,6 +14,7 @@ extern bool opt_prof_gdump; /* High-water memory dumping. */
|
|||||||
extern bool opt_prof_final; /* Final profile dumping. */
|
extern bool opt_prof_final; /* Final profile dumping. */
|
||||||
extern bool opt_prof_leak; /* Dump leak summary at exit. */
|
extern bool opt_prof_leak; /* Dump leak summary at exit. */
|
||||||
extern bool opt_prof_accum; /* Report cumulative bytes. */
|
extern bool opt_prof_accum; /* Report cumulative bytes. */
|
||||||
|
extern bool opt_prof_log; /* Turn logging on at boot. */
|
||||||
extern char opt_prof_prefix[
|
extern char opt_prof_prefix[
|
||||||
/* Minimize memory bloat for non-prof builds. */
|
/* Minimize memory bloat for non-prof builds. */
|
||||||
#ifdef JEMALLOC_PROF
|
#ifdef JEMALLOC_PROF
|
||||||
@ -45,7 +46,8 @@ extern size_t lg_prof_sample;
|
|||||||
void prof_alloc_rollback(tsd_t *tsd, prof_tctx_t *tctx, bool updated);
|
void prof_alloc_rollback(tsd_t *tsd, prof_tctx_t *tctx, bool updated);
|
||||||
void prof_malloc_sample_object(tsdn_t *tsdn, const void *ptr, size_t usize,
|
void prof_malloc_sample_object(tsdn_t *tsdn, const void *ptr, size_t usize,
|
||||||
prof_tctx_t *tctx);
|
prof_tctx_t *tctx);
|
||||||
void prof_free_sampled_object(tsd_t *tsd, size_t usize, prof_tctx_t *tctx);
|
void prof_free_sampled_object(tsd_t *tsd, const void *ptr, size_t usize,
|
||||||
|
prof_tctx_t *tctx);
|
||||||
void bt_init(prof_bt_t *bt, void **vec);
|
void bt_init(prof_bt_t *bt, void **vec);
|
||||||
void prof_backtrace(prof_bt_t *bt);
|
void prof_backtrace(prof_bt_t *bt);
|
||||||
prof_tctx_t *prof_lookup(tsd_t *tsd, prof_bt_t *bt);
|
prof_tctx_t *prof_lookup(tsd_t *tsd, prof_bt_t *bt);
|
||||||
@ -89,4 +91,15 @@ void prof_postfork_parent(tsdn_t *tsdn);
|
|||||||
void prof_postfork_child(tsdn_t *tsdn);
|
void prof_postfork_child(tsdn_t *tsdn);
|
||||||
void prof_sample_threshold_update(prof_tdata_t *tdata);
|
void prof_sample_threshold_update(prof_tdata_t *tdata);
|
||||||
|
|
||||||
|
bool prof_log_start(tsdn_t *tsdn, const char *filename);
|
||||||
|
bool prof_log_stop(tsdn_t *tsdn);
|
||||||
|
#ifdef JEMALLOC_JET
|
||||||
|
size_t prof_log_bt_count(void);
|
||||||
|
size_t prof_log_alloc_count(void);
|
||||||
|
size_t prof_log_thr_count(void);
|
||||||
|
bool prof_log_is_logging(void);
|
||||||
|
bool prof_log_rep_check(void);
|
||||||
|
void prof_log_dummy_set(bool new_value);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_PROF_EXTERNS_H */
|
#endif /* JEMALLOC_INTERNAL_PROF_EXTERNS_H */
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
#include "jemalloc/internal/mutex.h"
|
#include "jemalloc/internal/mutex.h"
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
prof_accum_add(tsdn_t *tsdn, prof_accum_t *prof_accum, uint64_t accumbytes) {
|
prof_accum_add(tsdn_t *tsdn, prof_accum_t *prof_accum,
|
||||||
|
uint64_t accumbytes) {
|
||||||
cassert(config_prof);
|
cassert(config_prof);
|
||||||
|
|
||||||
bool overflow;
|
bool overflow;
|
||||||
@ -42,7 +43,8 @@ prof_accum_add(tsdn_t *tsdn, prof_accum_t *prof_accum, uint64_t accumbytes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
prof_accum_cancel(tsdn_t *tsdn, prof_accum_t *prof_accum, size_t usize) {
|
prof_accum_cancel(tsdn_t *tsdn, prof_accum_t *prof_accum,
|
||||||
|
size_t usize) {
|
||||||
cassert(config_prof);
|
cassert(config_prof);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -55,15 +57,15 @@ prof_accum_cancel(tsdn_t *tsdn, prof_accum_t *prof_accum, size_t usize) {
|
|||||||
#ifdef JEMALLOC_ATOMIC_U64
|
#ifdef JEMALLOC_ATOMIC_U64
|
||||||
a0 = atomic_load_u64(&prof_accum->accumbytes, ATOMIC_RELAXED);
|
a0 = atomic_load_u64(&prof_accum->accumbytes, ATOMIC_RELAXED);
|
||||||
do {
|
do {
|
||||||
a1 = (a0 >= LARGE_MINCLASS - usize) ? a0 - (LARGE_MINCLASS -
|
a1 = (a0 >= SC_LARGE_MINCLASS - usize)
|
||||||
usize) : 0;
|
? a0 - (SC_LARGE_MINCLASS - usize) : 0;
|
||||||
} while (!atomic_compare_exchange_weak_u64(&prof_accum->accumbytes, &a0,
|
} while (!atomic_compare_exchange_weak_u64(&prof_accum->accumbytes, &a0,
|
||||||
a1, ATOMIC_RELAXED, ATOMIC_RELAXED));
|
a1, ATOMIC_RELAXED, ATOMIC_RELAXED));
|
||||||
#else
|
#else
|
||||||
malloc_mutex_lock(tsdn, &prof_accum->mtx);
|
malloc_mutex_lock(tsdn, &prof_accum->mtx);
|
||||||
a0 = prof_accum->accumbytes;
|
a0 = prof_accum->accumbytes;
|
||||||
a1 = (a0 >= LARGE_MINCLASS - usize) ? a0 - (LARGE_MINCLASS - usize) :
|
a1 = (a0 >= SC_LARGE_MINCLASS - usize)
|
||||||
0;
|
? a0 - (SC_LARGE_MINCLASS - usize) : 0;
|
||||||
prof_accum->accumbytes = a1;
|
prof_accum->accumbytes = a1;
|
||||||
malloc_mutex_unlock(tsdn, &prof_accum->mtx);
|
malloc_mutex_unlock(tsdn, &prof_accum->mtx);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#ifndef JEMALLOC_INTERNAL_PROF_INLINES_B_H
|
#ifndef JEMALLOC_INTERNAL_PROF_INLINES_B_H
|
||||||
#define JEMALLOC_INTERNAL_PROF_INLINES_B_H
|
#define JEMALLOC_INTERNAL_PROF_INLINES_B_H
|
||||||
|
|
||||||
|
#include "jemalloc/internal/safety_check.h"
|
||||||
#include "jemalloc/internal/sz.h"
|
#include "jemalloc/internal/sz.h"
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE bool
|
JEMALLOC_ALWAYS_INLINE bool
|
||||||
@ -61,6 +62,41 @@ prof_tctx_reset(tsdn_t *tsdn, const void *ptr, prof_tctx_t *tctx) {
|
|||||||
arena_prof_tctx_reset(tsdn, ptr, tctx);
|
arena_prof_tctx_reset(tsdn, ptr, tctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JEMALLOC_ALWAYS_INLINE nstime_t
|
||||||
|
prof_alloc_time_get(tsdn_t *tsdn, const void *ptr, alloc_ctx_t *alloc_ctx) {
|
||||||
|
cassert(config_prof);
|
||||||
|
assert(ptr != NULL);
|
||||||
|
|
||||||
|
return arena_prof_alloc_time_get(tsdn, ptr, alloc_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
|
prof_alloc_time_set(tsdn_t *tsdn, const void *ptr, alloc_ctx_t *alloc_ctx,
|
||||||
|
nstime_t t) {
|
||||||
|
cassert(config_prof);
|
||||||
|
assert(ptr != NULL);
|
||||||
|
|
||||||
|
arena_prof_alloc_time_set(tsdn, ptr, alloc_ctx, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_ALWAYS_INLINE bool
|
||||||
|
prof_sample_check(tsd_t *tsd, size_t usize, bool update) {
|
||||||
|
ssize_t check = update ? 0 : usize;
|
||||||
|
|
||||||
|
int64_t bytes_until_sample = tsd_bytes_until_sample_get(tsd);
|
||||||
|
if (update) {
|
||||||
|
bytes_until_sample -= usize;
|
||||||
|
if (tsd_nominal(tsd)) {
|
||||||
|
tsd_bytes_until_sample_set(tsd, bytes_until_sample);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (likely(bytes_until_sample >= check)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE bool
|
JEMALLOC_ALWAYS_INLINE bool
|
||||||
prof_sample_accum_update(tsd_t *tsd, size_t usize, bool update,
|
prof_sample_accum_update(tsd_t *tsd, size_t usize, bool update,
|
||||||
prof_tdata_t **tdata_out) {
|
prof_tdata_t **tdata_out) {
|
||||||
@ -68,6 +104,12 @@ prof_sample_accum_update(tsd_t *tsd, size_t usize, bool update,
|
|||||||
|
|
||||||
cassert(config_prof);
|
cassert(config_prof);
|
||||||
|
|
||||||
|
/* Fastpath: no need to load tdata */
|
||||||
|
if (likely(prof_sample_check(tsd, usize, update))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool booted = tsd_prof_tdata_get(tsd);
|
||||||
tdata = prof_tdata_get(tsd, true);
|
tdata = prof_tdata_get(tsd, true);
|
||||||
if (unlikely((uintptr_t)tdata <= (uintptr_t)PROF_TDATA_STATE_MAX)) {
|
if (unlikely((uintptr_t)tdata <= (uintptr_t)PROF_TDATA_STATE_MAX)) {
|
||||||
tdata = NULL;
|
tdata = NULL;
|
||||||
@ -81,12 +123,15 @@ prof_sample_accum_update(tsd_t *tsd, size_t usize, bool update,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (likely(tdata->bytes_until_sample >= usize)) {
|
/*
|
||||||
if (update) {
|
* If this was the first creation of tdata, then
|
||||||
tdata->bytes_until_sample -= usize;
|
* prof_tdata_get() reset bytes_until_sample, so decrement and
|
||||||
}
|
* check it again
|
||||||
|
*/
|
||||||
|
if (!booted && prof_sample_check(tsd, usize, update)) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
}
|
||||||
|
|
||||||
if (tsd_reentrancy_level_get(tsd) > 0) {
|
if (tsd_reentrancy_level_get(tsd) > 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -96,7 +141,6 @@ prof_sample_accum_update(tsd_t *tsd, size_t usize, bool update,
|
|||||||
}
|
}
|
||||||
return !tdata->active;
|
return !tdata->active;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE prof_tctx_t *
|
JEMALLOC_ALWAYS_INLINE prof_tctx_t *
|
||||||
prof_alloc_prep(tsd_t *tsd, size_t usize, bool prof_active, bool update) {
|
prof_alloc_prep(tsd_t *tsd, size_t usize, bool prof_active, bool update) {
|
||||||
@ -187,7 +231,7 @@ prof_realloc(tsd_t *tsd, const void *ptr, size_t usize, prof_tctx_t *tctx,
|
|||||||
* counters.
|
* counters.
|
||||||
*/
|
*/
|
||||||
if (unlikely(old_sampled)) {
|
if (unlikely(old_sampled)) {
|
||||||
prof_free_sampled_object(tsd, old_usize, old_tctx);
|
prof_free_sampled_object(tsd, ptr, old_usize, old_tctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,7 +243,7 @@ prof_free(tsd_t *tsd, const void *ptr, size_t usize, alloc_ctx_t *alloc_ctx) {
|
|||||||
assert(usize == isalloc(tsd_tsdn(tsd), ptr));
|
assert(usize == isalloc(tsd_tsdn(tsd), ptr));
|
||||||
|
|
||||||
if (unlikely((uintptr_t)tctx > (uintptr_t)1U)) {
|
if (unlikely((uintptr_t)tctx > (uintptr_t)1U)) {
|
||||||
prof_free_sampled_object(tsd, usize, tctx);
|
prof_free_sampled_object(tsd, ptr, usize, tctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +169,6 @@ struct prof_tdata_s {
|
|||||||
|
|
||||||
/* Sampling state. */
|
/* Sampling state. */
|
||||||
uint64_t prng_state;
|
uint64_t prng_state;
|
||||||
uint64_t bytes_until_sample;
|
|
||||||
|
|
||||||
/* State used to avoid dumping while operating on prof internals. */
|
/* State used to avoid dumping while operating on prof internals. */
|
||||||
bool enq;
|
bool enq;
|
||||||
|
77
deps/jemalloc/include/jemalloc/internal/quantum.h
vendored
Normal file
77
deps/jemalloc/include/jemalloc/internal/quantum.h
vendored
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#ifndef JEMALLOC_INTERNAL_QUANTUM_H
|
||||||
|
#define JEMALLOC_INTERNAL_QUANTUM_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Minimum allocation alignment is 2^LG_QUANTUM bytes (ignoring tiny size
|
||||||
|
* classes).
|
||||||
|
*/
|
||||||
|
#ifndef LG_QUANTUM
|
||||||
|
# if (defined(__i386__) || defined(_M_IX86))
|
||||||
|
# define LG_QUANTUM 4
|
||||||
|
# endif
|
||||||
|
# ifdef __ia64__
|
||||||
|
# define LG_QUANTUM 4
|
||||||
|
# endif
|
||||||
|
# ifdef __alpha__
|
||||||
|
# define LG_QUANTUM 4
|
||||||
|
# endif
|
||||||
|
# if (defined(__sparc64__) || defined(__sparcv9) || defined(__sparc_v9__))
|
||||||
|
# define LG_QUANTUM 4
|
||||||
|
# endif
|
||||||
|
# if (defined(__amd64__) || defined(__x86_64__) || defined(_M_X64))
|
||||||
|
# define LG_QUANTUM 4
|
||||||
|
# endif
|
||||||
|
# ifdef __arm__
|
||||||
|
# define LG_QUANTUM 3
|
||||||
|
# endif
|
||||||
|
# ifdef __aarch64__
|
||||||
|
# define LG_QUANTUM 4
|
||||||
|
# endif
|
||||||
|
# ifdef __hppa__
|
||||||
|
# define LG_QUANTUM 4
|
||||||
|
# endif
|
||||||
|
# ifdef __m68k__
|
||||||
|
# define LG_QUANTUM 3
|
||||||
|
# endif
|
||||||
|
# ifdef __mips__
|
||||||
|
# define LG_QUANTUM 3
|
||||||
|
# endif
|
||||||
|
# ifdef __nios2__
|
||||||
|
# define LG_QUANTUM 3
|
||||||
|
# endif
|
||||||
|
# ifdef __or1k__
|
||||||
|
# define LG_QUANTUM 3
|
||||||
|
# endif
|
||||||
|
# ifdef __powerpc__
|
||||||
|
# define LG_QUANTUM 4
|
||||||
|
# endif
|
||||||
|
# if defined(__riscv) || defined(__riscv__)
|
||||||
|
# define LG_QUANTUM 4
|
||||||
|
# endif
|
||||||
|
# ifdef __s390__
|
||||||
|
# define LG_QUANTUM 4
|
||||||
|
# endif
|
||||||
|
# if (defined (__SH3E__) || defined(__SH4_SINGLE__) || defined(__SH4__) || \
|
||||||
|
defined(__SH4_SINGLE_ONLY__))
|
||||||
|
# define LG_QUANTUM 4
|
||||||
|
# endif
|
||||||
|
# ifdef __tile__
|
||||||
|
# define LG_QUANTUM 4
|
||||||
|
# endif
|
||||||
|
# ifdef __le32__
|
||||||
|
# define LG_QUANTUM 4
|
||||||
|
# endif
|
||||||
|
# ifndef LG_QUANTUM
|
||||||
|
# error "Unknown minimum alignment for architecture; specify via "
|
||||||
|
"--with-lg-quantum"
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define QUANTUM ((size_t)(1U << LG_QUANTUM))
|
||||||
|
#define QUANTUM_MASK (QUANTUM - 1)
|
||||||
|
|
||||||
|
/* Return the smallest quantum multiple that is >= a. */
|
||||||
|
#define QUANTUM_CEILING(a) \
|
||||||
|
(((a) + QUANTUM_MASK) & ~QUANTUM_MASK)
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_INTERNAL_QUANTUM_H */
|
70
deps/jemalloc/include/jemalloc/internal/rtree.h
vendored
70
deps/jemalloc/include/jemalloc/internal/rtree.h
vendored
@ -4,7 +4,7 @@
|
|||||||
#include "jemalloc/internal/atomic.h"
|
#include "jemalloc/internal/atomic.h"
|
||||||
#include "jemalloc/internal/mutex.h"
|
#include "jemalloc/internal/mutex.h"
|
||||||
#include "jemalloc/internal/rtree_tsd.h"
|
#include "jemalloc/internal/rtree_tsd.h"
|
||||||
#include "jemalloc/internal/size_classes.h"
|
#include "jemalloc/internal/sc.h"
|
||||||
#include "jemalloc/internal/tsd.h"
|
#include "jemalloc/internal/tsd.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -31,7 +31,7 @@
|
|||||||
# error Unsupported number of significant virtual address bits
|
# error Unsupported number of significant virtual address bits
|
||||||
#endif
|
#endif
|
||||||
/* Use compact leaf representation if virtual address encoding allows. */
|
/* Use compact leaf representation if virtual address encoding allows. */
|
||||||
#if RTREE_NHIB >= LG_CEIL_NSIZES
|
#if RTREE_NHIB >= LG_CEIL(SC_NSIZES)
|
||||||
# define RTREE_LEAF_COMPACT
|
# define RTREE_LEAF_COMPACT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -170,8 +170,8 @@ rtree_subkey(uintptr_t key, unsigned level) {
|
|||||||
*/
|
*/
|
||||||
# ifdef RTREE_LEAF_COMPACT
|
# ifdef RTREE_LEAF_COMPACT
|
||||||
JEMALLOC_ALWAYS_INLINE uintptr_t
|
JEMALLOC_ALWAYS_INLINE uintptr_t
|
||||||
rtree_leaf_elm_bits_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm,
|
rtree_leaf_elm_bits_read(tsdn_t *tsdn, rtree_t *rtree,
|
||||||
bool dependent) {
|
rtree_leaf_elm_t *elm, bool dependent) {
|
||||||
return (uintptr_t)atomic_load_p(&elm->le_bits, dependent
|
return (uintptr_t)atomic_load_p(&elm->le_bits, dependent
|
||||||
? ATOMIC_RELAXED : ATOMIC_ACQUIRE);
|
? ATOMIC_RELAXED : ATOMIC_ACQUIRE);
|
||||||
}
|
}
|
||||||
@ -208,7 +208,7 @@ rtree_leaf_elm_bits_slab_get(uintptr_t bits) {
|
|||||||
# endif
|
# endif
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE extent_t *
|
JEMALLOC_ALWAYS_INLINE extent_t *
|
||||||
rtree_leaf_elm_extent_read(UNUSED tsdn_t *tsdn, UNUSED rtree_t *rtree,
|
rtree_leaf_elm_extent_read(tsdn_t *tsdn, rtree_t *rtree,
|
||||||
rtree_leaf_elm_t *elm, bool dependent) {
|
rtree_leaf_elm_t *elm, bool dependent) {
|
||||||
#ifdef RTREE_LEAF_COMPACT
|
#ifdef RTREE_LEAF_COMPACT
|
||||||
uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, dependent);
|
uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, dependent);
|
||||||
@ -221,7 +221,7 @@ rtree_leaf_elm_extent_read(UNUSED tsdn_t *tsdn, UNUSED rtree_t *rtree,
|
|||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE szind_t
|
JEMALLOC_ALWAYS_INLINE szind_t
|
||||||
rtree_leaf_elm_szind_read(UNUSED tsdn_t *tsdn, UNUSED rtree_t *rtree,
|
rtree_leaf_elm_szind_read(tsdn_t *tsdn, rtree_t *rtree,
|
||||||
rtree_leaf_elm_t *elm, bool dependent) {
|
rtree_leaf_elm_t *elm, bool dependent) {
|
||||||
#ifdef RTREE_LEAF_COMPACT
|
#ifdef RTREE_LEAF_COMPACT
|
||||||
uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, dependent);
|
uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, dependent);
|
||||||
@ -233,7 +233,7 @@ rtree_leaf_elm_szind_read(UNUSED tsdn_t *tsdn, UNUSED rtree_t *rtree,
|
|||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE bool
|
JEMALLOC_ALWAYS_INLINE bool
|
||||||
rtree_leaf_elm_slab_read(UNUSED tsdn_t *tsdn, UNUSED rtree_t *rtree,
|
rtree_leaf_elm_slab_read(tsdn_t *tsdn, rtree_t *rtree,
|
||||||
rtree_leaf_elm_t *elm, bool dependent) {
|
rtree_leaf_elm_t *elm, bool dependent) {
|
||||||
#ifdef RTREE_LEAF_COMPACT
|
#ifdef RTREE_LEAF_COMPACT
|
||||||
uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, dependent);
|
uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, dependent);
|
||||||
@ -245,7 +245,7 @@ rtree_leaf_elm_slab_read(UNUSED tsdn_t *tsdn, UNUSED rtree_t *rtree,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
rtree_leaf_elm_extent_write(UNUSED tsdn_t *tsdn, UNUSED rtree_t *rtree,
|
rtree_leaf_elm_extent_write(tsdn_t *tsdn, rtree_t *rtree,
|
||||||
rtree_leaf_elm_t *elm, extent_t *extent) {
|
rtree_leaf_elm_t *elm, extent_t *extent) {
|
||||||
#ifdef RTREE_LEAF_COMPACT
|
#ifdef RTREE_LEAF_COMPACT
|
||||||
uintptr_t old_bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, true);
|
uintptr_t old_bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, true);
|
||||||
@ -259,9 +259,9 @@ rtree_leaf_elm_extent_write(UNUSED tsdn_t *tsdn, UNUSED rtree_t *rtree,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
rtree_leaf_elm_szind_write(UNUSED tsdn_t *tsdn, UNUSED rtree_t *rtree,
|
rtree_leaf_elm_szind_write(tsdn_t *tsdn, rtree_t *rtree,
|
||||||
rtree_leaf_elm_t *elm, szind_t szind) {
|
rtree_leaf_elm_t *elm, szind_t szind) {
|
||||||
assert(szind <= NSIZES);
|
assert(szind <= SC_NSIZES);
|
||||||
|
|
||||||
#ifdef RTREE_LEAF_COMPACT
|
#ifdef RTREE_LEAF_COMPACT
|
||||||
uintptr_t old_bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm,
|
uintptr_t old_bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm,
|
||||||
@ -277,7 +277,7 @@ rtree_leaf_elm_szind_write(UNUSED tsdn_t *tsdn, UNUSED rtree_t *rtree,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
rtree_leaf_elm_slab_write(UNUSED tsdn_t *tsdn, UNUSED rtree_t *rtree,
|
rtree_leaf_elm_slab_write(tsdn_t *tsdn, rtree_t *rtree,
|
||||||
rtree_leaf_elm_t *elm, bool slab) {
|
rtree_leaf_elm_t *elm, bool slab) {
|
||||||
#ifdef RTREE_LEAF_COMPACT
|
#ifdef RTREE_LEAF_COMPACT
|
||||||
uintptr_t old_bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm,
|
uintptr_t old_bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm,
|
||||||
@ -292,8 +292,8 @@ rtree_leaf_elm_slab_write(UNUSED tsdn_t *tsdn, UNUSED rtree_t *rtree,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
rtree_leaf_elm_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm,
|
rtree_leaf_elm_write(tsdn_t *tsdn, rtree_t *rtree,
|
||||||
extent_t *extent, szind_t szind, bool slab) {
|
rtree_leaf_elm_t *elm, extent_t *extent, szind_t szind, bool slab) {
|
||||||
#ifdef RTREE_LEAF_COMPACT
|
#ifdef RTREE_LEAF_COMPACT
|
||||||
uintptr_t bits = ((uintptr_t)szind << LG_VADDR) |
|
uintptr_t bits = ((uintptr_t)szind << LG_VADDR) |
|
||||||
((uintptr_t)extent & (((uintptr_t)0x1 << LG_VADDR) - 1)) |
|
((uintptr_t)extent & (((uintptr_t)0x1 << LG_VADDR) - 1)) |
|
||||||
@ -313,7 +313,7 @@ rtree_leaf_elm_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm,
|
|||||||
static inline void
|
static inline void
|
||||||
rtree_leaf_elm_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree,
|
rtree_leaf_elm_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree,
|
||||||
rtree_leaf_elm_t *elm, szind_t szind, bool slab) {
|
rtree_leaf_elm_t *elm, szind_t szind, bool slab) {
|
||||||
assert(!slab || szind < NBINS);
|
assert(!slab || szind < SC_NBINS);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The caller implicitly assures that it is the only writer to the szind
|
* The caller implicitly assures that it is the only writer to the szind
|
||||||
@ -429,7 +429,7 @@ rtree_szind_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
|||||||
rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key,
|
rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key,
|
||||||
dependent);
|
dependent);
|
||||||
if (!dependent && elm == NULL) {
|
if (!dependent && elm == NULL) {
|
||||||
return NSIZES;
|
return SC_NSIZES;
|
||||||
}
|
}
|
||||||
return rtree_leaf_elm_szind_read(tsdn, rtree, elm, dependent);
|
return rtree_leaf_elm_szind_read(tsdn, rtree, elm, dependent);
|
||||||
}
|
}
|
||||||
@ -452,6 +452,42 @@ rtree_extent_szind_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to read szind_slab from the L1 cache. Returns true on a hit,
|
||||||
|
* and fills in r_szind and r_slab. Otherwise returns false.
|
||||||
|
*
|
||||||
|
* Key is allowed to be NULL in order to save an extra branch on the
|
||||||
|
* fastpath. returns false in this case.
|
||||||
|
*/
|
||||||
|
JEMALLOC_ALWAYS_INLINE bool
|
||||||
|
rtree_szind_slab_read_fast(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
||||||
|
uintptr_t key, szind_t *r_szind, bool *r_slab) {
|
||||||
|
rtree_leaf_elm_t *elm;
|
||||||
|
|
||||||
|
size_t slot = rtree_cache_direct_map(key);
|
||||||
|
uintptr_t leafkey = rtree_leafkey(key);
|
||||||
|
assert(leafkey != RTREE_LEAFKEY_INVALID);
|
||||||
|
|
||||||
|
if (likely(rtree_ctx->cache[slot].leafkey == leafkey)) {
|
||||||
|
rtree_leaf_elm_t *leaf = rtree_ctx->cache[slot].leaf;
|
||||||
|
assert(leaf != NULL);
|
||||||
|
uintptr_t subkey = rtree_subkey(key, RTREE_HEIGHT-1);
|
||||||
|
elm = &leaf[subkey];
|
||||||
|
|
||||||
|
#ifdef RTREE_LEAF_COMPACT
|
||||||
|
uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree,
|
||||||
|
elm, true);
|
||||||
|
*r_szind = rtree_leaf_elm_bits_szind_get(bits);
|
||||||
|
*r_slab = rtree_leaf_elm_bits_slab_get(bits);
|
||||||
|
#else
|
||||||
|
*r_szind = rtree_leaf_elm_szind_read(tsdn, rtree, elm, true);
|
||||||
|
*r_slab = rtree_leaf_elm_slab_read(tsdn, rtree, elm, true);
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
JEMALLOC_ALWAYS_INLINE bool
|
JEMALLOC_ALWAYS_INLINE bool
|
||||||
rtree_szind_slab_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
rtree_szind_slab_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
||||||
uintptr_t key, bool dependent, szind_t *r_szind, bool *r_slab) {
|
uintptr_t key, bool dependent, szind_t *r_szind, bool *r_slab) {
|
||||||
@ -474,7 +510,7 @@ rtree_szind_slab_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
|||||||
static inline void
|
static inline void
|
||||||
rtree_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
rtree_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
||||||
uintptr_t key, szind_t szind, bool slab) {
|
uintptr_t key, szind_t szind, bool slab) {
|
||||||
assert(!slab || szind < NBINS);
|
assert(!slab || szind < SC_NBINS);
|
||||||
|
|
||||||
rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key, true);
|
rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key, true);
|
||||||
rtree_leaf_elm_szind_slab_update(tsdn, rtree, elm, szind, slab);
|
rtree_leaf_elm_szind_slab_update(tsdn, rtree, elm, szind, slab);
|
||||||
@ -486,7 +522,7 @@ rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
|||||||
rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key, true);
|
rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key, true);
|
||||||
assert(rtree_leaf_elm_extent_read(tsdn, rtree, elm, false) !=
|
assert(rtree_leaf_elm_extent_read(tsdn, rtree, elm, false) !=
|
||||||
NULL);
|
NULL);
|
||||||
rtree_leaf_elm_write(tsdn, rtree, elm, NULL, NSIZES, false);
|
rtree_leaf_elm_write(tsdn, rtree, elm, NULL, SC_NSIZES, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_RTREE_H */
|
#endif /* JEMALLOC_INTERNAL_RTREE_H */
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
* Zero initializer required for tsd initialization only. Proper initialization
|
* Zero initializer required for tsd initialization only. Proper initialization
|
||||||
* done via rtree_ctx_data_init().
|
* done via rtree_ctx_data_init().
|
||||||
*/
|
*/
|
||||||
#define RTREE_CTX_ZERO_INITIALIZER {{{0}}, {{0}}}
|
#define RTREE_CTX_ZERO_INITIALIZER {{{0, 0}}, {{0, 0}}}
|
||||||
|
|
||||||
|
|
||||||
typedef struct rtree_leaf_elm_s rtree_leaf_elm_t;
|
typedef struct rtree_leaf_elm_s rtree_leaf_elm_t;
|
||||||
|
26
deps/jemalloc/include/jemalloc/internal/safety_check.h
vendored
Normal file
26
deps/jemalloc/include/jemalloc/internal/safety_check.h
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#ifndef JEMALLOC_INTERNAL_SAFETY_CHECK_H
|
||||||
|
#define JEMALLOC_INTERNAL_SAFETY_CHECK_H
|
||||||
|
|
||||||
|
void safety_check_fail(const char *format, ...);
|
||||||
|
/* Can set to NULL for a default. */
|
||||||
|
void safety_check_set_abort(void (*abort_fn)());
|
||||||
|
|
||||||
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
|
safety_check_set_redzone(void *ptr, size_t usize, size_t bumped_usize) {
|
||||||
|
assert(usize < bumped_usize);
|
||||||
|
for (size_t i = usize; i < bumped_usize && i < usize + 32; ++i) {
|
||||||
|
*((unsigned char *)ptr + i) = 0xBC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
|
safety_check_verify_redzone(const void *ptr, size_t usize, size_t bumped_usize)
|
||||||
|
{
|
||||||
|
for (size_t i = usize; i < bumped_usize && i < usize + 32; ++i) {
|
||||||
|
if (unlikely(*((unsigned char *)ptr + i) != 0xBC)) {
|
||||||
|
safety_check_fail("Use after free error\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /*JEMALLOC_INTERNAL_SAFETY_CHECK_H */
|
333
deps/jemalloc/include/jemalloc/internal/sc.h
vendored
Normal file
333
deps/jemalloc/include/jemalloc/internal/sc.h
vendored
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
#ifndef JEMALLOC_INTERNAL_SC_H
|
||||||
|
#define JEMALLOC_INTERNAL_SC_H
|
||||||
|
|
||||||
|
#include "jemalloc/internal/jemalloc_internal_types.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Size class computations:
|
||||||
|
*
|
||||||
|
* These are a little tricky; we'll first start by describing how things
|
||||||
|
* generally work, and then describe some of the details.
|
||||||
|
*
|
||||||
|
* Ignore the first few size classes for a moment. We can then split all the
|
||||||
|
* remaining size classes into groups. The size classes in a group are spaced
|
||||||
|
* such that they cover allocation request sizes in a power-of-2 range. The
|
||||||
|
* power of two is called the base of the group, and the size classes in it
|
||||||
|
* satisfy allocations in the half-open range (base, base * 2]. There are
|
||||||
|
* SC_NGROUP size classes in each group, equally spaced in the range, so that
|
||||||
|
* each one covers allocations for base / SC_NGROUP possible allocation sizes.
|
||||||
|
* We call that value (base / SC_NGROUP) the delta of the group. Each size class
|
||||||
|
* is delta larger than the one before it (including the initial size class in a
|
||||||
|
* group, which is delta larger than base, the largest size class in the
|
||||||
|
* previous group).
|
||||||
|
* To make the math all work out nicely, we require that SC_NGROUP is a power of
|
||||||
|
* two, and define it in terms of SC_LG_NGROUP. We'll often talk in terms of
|
||||||
|
* lg_base and lg_delta. For each of these groups then, we have that
|
||||||
|
* lg_delta == lg_base - SC_LG_NGROUP.
|
||||||
|
* The size classes in a group with a given lg_base and lg_delta (which, recall,
|
||||||
|
* can be computed from lg_base for these groups) are therefore:
|
||||||
|
* base + 1 * delta
|
||||||
|
* which covers allocations in (base, base + 1 * delta]
|
||||||
|
* base + 2 * delta
|
||||||
|
* which covers allocations in (base + 1 * delta, base + 2 * delta].
|
||||||
|
* base + 3 * delta
|
||||||
|
* which covers allocations in (base + 2 * delta, base + 3 * delta].
|
||||||
|
* ...
|
||||||
|
* base + SC_NGROUP * delta ( == 2 * base)
|
||||||
|
* which covers allocations in (base + (SC_NGROUP - 1) * delta, 2 * base].
|
||||||
|
* (Note that currently SC_NGROUP is always 4, so the "..." is empty in
|
||||||
|
* practice.)
|
||||||
|
* Note that the last size class in the group is the next power of two (after
|
||||||
|
* base), so that we've set up the induction correctly for the next group's
|
||||||
|
* selection of delta.
|
||||||
|
*
|
||||||
|
* Now, let's start considering the first few size classes. Two extra constants
|
||||||
|
* come into play here: LG_QUANTUM and SC_LG_TINY_MIN. LG_QUANTUM ensures
|
||||||
|
* correct platform alignment; all objects of size (1 << LG_QUANTUM) or larger
|
||||||
|
* are at least (1 << LG_QUANTUM) aligned; this can be used to ensure that we
|
||||||
|
* never return improperly aligned memory, by making (1 << LG_QUANTUM) equal the
|
||||||
|
* highest required alignment of a platform. For allocation sizes smaller than
|
||||||
|
* (1 << LG_QUANTUM) though, we can be more relaxed (since we don't support
|
||||||
|
* platforms with types with alignment larger than their size). To allow such
|
||||||
|
* allocations (without wasting space unnecessarily), we introduce tiny size
|
||||||
|
* classes; one per power of two, up until we hit the quantum size. There are
|
||||||
|
* therefore LG_QUANTUM - SC_LG_TINY_MIN such size classes.
|
||||||
|
*
|
||||||
|
* Next, we have a size class of size (1 << LG_QUANTUM). This can't be the
|
||||||
|
* start of a group in the sense we described above (covering a power of two
|
||||||
|
* range) since, if we divided into it to pick a value of delta, we'd get a
|
||||||
|
* delta smaller than (1 << LG_QUANTUM) for sizes >= (1 << LG_QUANTUM), which
|
||||||
|
* is against the rules.
|
||||||
|
*
|
||||||
|
* The first base we can divide by SC_NGROUP while still being at least
|
||||||
|
* (1 << LG_QUANTUM) is SC_NGROUP * (1 << LG_QUANTUM). We can get there by
|
||||||
|
* having SC_NGROUP size classes, spaced (1 << LG_QUANTUM) apart. These size
|
||||||
|
* classes are:
|
||||||
|
* 1 * (1 << LG_QUANTUM)
|
||||||
|
* 2 * (1 << LG_QUANTUM)
|
||||||
|
* 3 * (1 << LG_QUANTUM)
|
||||||
|
* ... (although, as above, this "..." is empty in practice)
|
||||||
|
* SC_NGROUP * (1 << LG_QUANTUM).
|
||||||
|
*
|
||||||
|
* There are SC_NGROUP of these size classes, so we can regard it as a sort of
|
||||||
|
* pseudo-group, even though it spans multiple powers of 2, is divided
|
||||||
|
* differently, and both starts and ends on a power of 2 (as opposed to just
|
||||||
|
* ending). SC_NGROUP is itself a power of two, so the first group after the
|
||||||
|
* pseudo-group has the power-of-two base SC_NGROUP * (1 << LG_QUANTUM), for a
|
||||||
|
* lg_base of LG_QUANTUM + SC_LG_NGROUP. We can divide this base into SC_NGROUP
|
||||||
|
* sizes without violating our LG_QUANTUM requirements, so we can safely set
|
||||||
|
* lg_delta = lg_base - SC_LG_GROUP (== LG_QUANTUM).
|
||||||
|
*
|
||||||
|
* So, in order, the size classes are:
|
||||||
|
*
|
||||||
|
* Tiny size classes:
|
||||||
|
* - Count: LG_QUANTUM - SC_LG_TINY_MIN.
|
||||||
|
* - Sizes:
|
||||||
|
* 1 << SC_LG_TINY_MIN
|
||||||
|
* 1 << (SC_LG_TINY_MIN + 1)
|
||||||
|
* 1 << (SC_LG_TINY_MIN + 2)
|
||||||
|
* ...
|
||||||
|
* 1 << (LG_QUANTUM - 1)
|
||||||
|
*
|
||||||
|
* Initial pseudo-group:
|
||||||
|
* - Count: SC_NGROUP
|
||||||
|
* - Sizes:
|
||||||
|
* 1 * (1 << LG_QUANTUM)
|
||||||
|
* 2 * (1 << LG_QUANTUM)
|
||||||
|
* 3 * (1 << LG_QUANTUM)
|
||||||
|
* ...
|
||||||
|
* SC_NGROUP * (1 << LG_QUANTUM)
|
||||||
|
*
|
||||||
|
* Regular group 0:
|
||||||
|
* - Count: SC_NGROUP
|
||||||
|
* - Sizes:
|
||||||
|
* (relative to lg_base of LG_QUANTUM + SC_LG_NGROUP and lg_delta of
|
||||||
|
* lg_base - SC_LG_NGROUP)
|
||||||
|
* (1 << lg_base) + 1 * (1 << lg_delta)
|
||||||
|
* (1 << lg_base) + 2 * (1 << lg_delta)
|
||||||
|
* (1 << lg_base) + 3 * (1 << lg_delta)
|
||||||
|
* ...
|
||||||
|
* (1 << lg_base) + SC_NGROUP * (1 << lg_delta) [ == (1 << (lg_base + 1)) ]
|
||||||
|
*
|
||||||
|
* Regular group 1:
|
||||||
|
* - Count: SC_NGROUP
|
||||||
|
* - Sizes:
|
||||||
|
* (relative to lg_base of LG_QUANTUM + SC_LG_NGROUP + 1 and lg_delta of
|
||||||
|
* lg_base - SC_LG_NGROUP)
|
||||||
|
* (1 << lg_base) + 1 * (1 << lg_delta)
|
||||||
|
* (1 << lg_base) + 2 * (1 << lg_delta)
|
||||||
|
* (1 << lg_base) + 3 * (1 << lg_delta)
|
||||||
|
* ...
|
||||||
|
* (1 << lg_base) + SC_NGROUP * (1 << lg_delta) [ == (1 << (lg_base + 1)) ]
|
||||||
|
*
|
||||||
|
* ...
|
||||||
|
*
|
||||||
|
* Regular group N:
|
||||||
|
* - Count: SC_NGROUP
|
||||||
|
* - Sizes:
|
||||||
|
* (relative to lg_base of LG_QUANTUM + SC_LG_NGROUP + N and lg_delta of
|
||||||
|
* lg_base - SC_LG_NGROUP)
|
||||||
|
* (1 << lg_base) + 1 * (1 << lg_delta)
|
||||||
|
* (1 << lg_base) + 2 * (1 << lg_delta)
|
||||||
|
* (1 << lg_base) + 3 * (1 << lg_delta)
|
||||||
|
* ...
|
||||||
|
* (1 << lg_base) + SC_NGROUP * (1 << lg_delta) [ == (1 << (lg_base + 1)) ]
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Representation of metadata:
|
||||||
|
* To make the math easy, we'll mostly work in lg quantities. We record lg_base,
|
||||||
|
* lg_delta, and ndelta (i.e. number of deltas above the base) on a
|
||||||
|
* per-size-class basis, and maintain the invariant that, across all size
|
||||||
|
* classes, size == (1 << lg_base) + ndelta * (1 << lg_delta).
|
||||||
|
*
|
||||||
|
* For regular groups (i.e. those with lg_base >= LG_QUANTUM + SC_LG_NGROUP),
|
||||||
|
* lg_delta is lg_base - SC_LG_NGROUP, and ndelta goes from 1 to SC_NGROUP.
|
||||||
|
*
|
||||||
|
* For the initial tiny size classes (if any), lg_base is lg(size class size).
|
||||||
|
* lg_delta is lg_base for the first size class, and lg_base - 1 for all
|
||||||
|
* subsequent ones. ndelta is always 0.
|
||||||
|
*
|
||||||
|
* For the pseudo-group, if there are no tiny size classes, then we set
|
||||||
|
* lg_base == LG_QUANTUM, lg_delta == LG_QUANTUM, and have ndelta range from 0
|
||||||
|
* to SC_NGROUP - 1. (Note that delta == base, so base + (SC_NGROUP - 1) * delta
|
||||||
|
* is just SC_NGROUP * base, or (1 << (SC_LG_NGROUP + LG_QUANTUM)), so we do
|
||||||
|
* indeed get a power of two that way). If there *are* tiny size classes, then
|
||||||
|
* the first size class needs to have lg_delta relative to the largest tiny size
|
||||||
|
* class. We therefore set lg_base == LG_QUANTUM - 1,
|
||||||
|
* lg_delta == LG_QUANTUM - 1, and ndelta == 1, keeping the rest of the
|
||||||
|
* pseudo-group the same.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Other terminology:
|
||||||
|
* "Small" size classes mean those that are allocated out of bins, which is the
|
||||||
|
* same as those that are slab allocated.
|
||||||
|
* "Large" size classes are those that are not small. The cutoff for counting as
|
||||||
|
* large is page size * group size.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Size class N + (1 << SC_LG_NGROUP) twice the size of size class N.
|
||||||
|
*/
|
||||||
|
#define SC_LG_NGROUP 2
|
||||||
|
#define SC_LG_TINY_MIN 3
|
||||||
|
|
||||||
|
#if SC_LG_TINY_MIN == 0
|
||||||
|
/* The div module doesn't support division by 1, which this would require. */
|
||||||
|
#error "Unsupported LG_TINY_MIN"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The definitions below are all determined by the above settings and system
|
||||||
|
* characteristics.
|
||||||
|
*/
|
||||||
|
#define SC_NGROUP (1ULL << SC_LG_NGROUP)
|
||||||
|
#define SC_PTR_BITS ((1ULL << LG_SIZEOF_PTR) * 8)
|
||||||
|
#define SC_NTINY (LG_QUANTUM - SC_LG_TINY_MIN)
|
||||||
|
#define SC_LG_TINY_MAXCLASS (LG_QUANTUM > SC_LG_TINY_MIN ? LG_QUANTUM - 1 : -1)
|
||||||
|
#define SC_NPSEUDO SC_NGROUP
|
||||||
|
#define SC_LG_FIRST_REGULAR_BASE (LG_QUANTUM + SC_LG_NGROUP)
|
||||||
|
/*
|
||||||
|
* We cap allocations to be less than 2 ** (ptr_bits - 1), so the highest base
|
||||||
|
* we need is 2 ** (ptr_bits - 2). (This also means that the last group is 1
|
||||||
|
* size class shorter than the others).
|
||||||
|
* We could probably save some space in arenas by capping this at LG_VADDR size.
|
||||||
|
*/
|
||||||
|
#define SC_LG_BASE_MAX (SC_PTR_BITS - 2)
|
||||||
|
#define SC_NREGULAR (SC_NGROUP * \
|
||||||
|
(SC_LG_BASE_MAX - SC_LG_FIRST_REGULAR_BASE + 1) - 1)
|
||||||
|
#define SC_NSIZES (SC_NTINY + SC_NPSEUDO + SC_NREGULAR)
|
||||||
|
|
||||||
|
/* The number of size classes that are a multiple of the page size. */
|
||||||
|
#define SC_NPSIZES ( \
|
||||||
|
/* Start with all the size classes. */ \
|
||||||
|
SC_NSIZES \
|
||||||
|
/* Subtract out those groups with too small a base. */ \
|
||||||
|
- (LG_PAGE - 1 - SC_LG_FIRST_REGULAR_BASE) * SC_NGROUP \
|
||||||
|
/* And the pseudo-group. */ \
|
||||||
|
- SC_NPSEUDO \
|
||||||
|
/* And the tiny group. */ \
|
||||||
|
- SC_NTINY \
|
||||||
|
/* Sizes where ndelta*delta is not a multiple of the page size. */ \
|
||||||
|
- (SC_LG_NGROUP * SC_NGROUP))
|
||||||
|
/*
|
||||||
|
* Note that the last line is computed as the sum of the second column in the
|
||||||
|
* following table:
|
||||||
|
* lg(base) | count of sizes to exclude
|
||||||
|
* ------------------------------|-----------------------------
|
||||||
|
* LG_PAGE - 1 | SC_NGROUP - 1
|
||||||
|
* LG_PAGE | SC_NGROUP - 1
|
||||||
|
* LG_PAGE + 1 | SC_NGROUP - 2
|
||||||
|
* LG_PAGE + 2 | SC_NGROUP - 4
|
||||||
|
* ... | ...
|
||||||
|
* LG_PAGE + (SC_LG_NGROUP - 1) | SC_NGROUP - (SC_NGROUP / 2)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We declare a size class is binnable if size < page size * group. Or, in other
|
||||||
|
* words, lg(size) < lg(page size) + lg(group size).
|
||||||
|
*/
|
||||||
|
#define SC_NBINS ( \
|
||||||
|
/* Sub-regular size classes. */ \
|
||||||
|
SC_NTINY + SC_NPSEUDO \
|
||||||
|
/* Groups with lg_regular_min_base <= lg_base <= lg_base_max */ \
|
||||||
|
+ SC_NGROUP * (LG_PAGE + SC_LG_NGROUP - SC_LG_FIRST_REGULAR_BASE) \
|
||||||
|
/* Last SC of the last group hits the bound exactly; exclude it. */ \
|
||||||
|
- 1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The size2index_tab lookup table uses uint8_t to encode each bin index, so we
|
||||||
|
* cannot support more than 256 small size classes.
|
||||||
|
*/
|
||||||
|
#if (SC_NBINS > 256)
|
||||||
|
# error "Too many small size classes"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The largest size class in the lookup table. */
|
||||||
|
#define SC_LOOKUP_MAXCLASS ((size_t)1 << 12)
|
||||||
|
|
||||||
|
/* Internal, only used for the definition of SC_SMALL_MAXCLASS. */
|
||||||
|
#define SC_SMALL_MAX_BASE ((size_t)1 << (LG_PAGE + SC_LG_NGROUP - 1))
|
||||||
|
#define SC_SMALL_MAX_DELTA ((size_t)1 << (LG_PAGE - 1))
|
||||||
|
|
||||||
|
/* The largest size class allocated out of a slab. */
|
||||||
|
#define SC_SMALL_MAXCLASS (SC_SMALL_MAX_BASE \
|
||||||
|
+ (SC_NGROUP - 1) * SC_SMALL_MAX_DELTA)
|
||||||
|
|
||||||
|
/* The smallest size class not allocated out of a slab. */
|
||||||
|
#define SC_LARGE_MINCLASS ((size_t)1ULL << (LG_PAGE + SC_LG_NGROUP))
|
||||||
|
#define SC_LG_LARGE_MINCLASS (LG_PAGE + SC_LG_NGROUP)
|
||||||
|
|
||||||
|
/* Internal; only used for the definition of SC_LARGE_MAXCLASS. */
|
||||||
|
#define SC_MAX_BASE ((size_t)1 << (SC_PTR_BITS - 2))
|
||||||
|
#define SC_MAX_DELTA ((size_t)1 << (SC_PTR_BITS - 2 - SC_LG_NGROUP))
|
||||||
|
|
||||||
|
/* The largest size class supported. */
|
||||||
|
#define SC_LARGE_MAXCLASS (SC_MAX_BASE + (SC_NGROUP - 1) * SC_MAX_DELTA)
|
||||||
|
|
||||||
|
typedef struct sc_s sc_t;
|
||||||
|
struct sc_s {
|
||||||
|
/* Size class index, or -1 if not a valid size class. */
|
||||||
|
int index;
|
||||||
|
/* Lg group base size (no deltas added). */
|
||||||
|
int lg_base;
|
||||||
|
/* Lg delta to previous size class. */
|
||||||
|
int lg_delta;
|
||||||
|
/* Delta multiplier. size == 1<<lg_base + ndelta<<lg_delta */
|
||||||
|
int ndelta;
|
||||||
|
/*
|
||||||
|
* True if the size class is a multiple of the page size, false
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
bool psz;
|
||||||
|
/*
|
||||||
|
* True if the size class is a small, bin, size class. False otherwise.
|
||||||
|
*/
|
||||||
|
bool bin;
|
||||||
|
/* The slab page count if a small bin size class, 0 otherwise. */
|
||||||
|
int pgs;
|
||||||
|
/* Same as lg_delta if a lookup table size class, 0 otherwise. */
|
||||||
|
int lg_delta_lookup;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct sc_data_s sc_data_t;
|
||||||
|
struct sc_data_s {
|
||||||
|
/* Number of tiny size classes. */
|
||||||
|
unsigned ntiny;
|
||||||
|
/* Number of bins supported by the lookup table. */
|
||||||
|
int nlbins;
|
||||||
|
/* Number of small size class bins. */
|
||||||
|
int nbins;
|
||||||
|
/* Number of size classes. */
|
||||||
|
int nsizes;
|
||||||
|
/* Number of bits required to store NSIZES. */
|
||||||
|
int lg_ceil_nsizes;
|
||||||
|
/* Number of size classes that are a multiple of (1U << LG_PAGE). */
|
||||||
|
unsigned npsizes;
|
||||||
|
/* Lg of maximum tiny size class (or -1, if none). */
|
||||||
|
int lg_tiny_maxclass;
|
||||||
|
/* Maximum size class included in lookup table. */
|
||||||
|
size_t lookup_maxclass;
|
||||||
|
/* Maximum small size class. */
|
||||||
|
size_t small_maxclass;
|
||||||
|
/* Lg of minimum large size class. */
|
||||||
|
int lg_large_minclass;
|
||||||
|
/* The minimum large size class. */
|
||||||
|
size_t large_minclass;
|
||||||
|
/* Maximum (large) size class. */
|
||||||
|
size_t large_maxclass;
|
||||||
|
/* True if the sc_data_t has been initialized (for debugging only). */
|
||||||
|
bool initialized;
|
||||||
|
|
||||||
|
sc_t sc[SC_NSIZES];
|
||||||
|
};
|
||||||
|
|
||||||
|
void sc_data_init(sc_data_t *data);
|
||||||
|
/*
|
||||||
|
* Updates slab sizes in [begin, end] to be pgs pages in length, if possible.
|
||||||
|
* Otherwise, does its best to accomodate the request.
|
||||||
|
*/
|
||||||
|
void sc_data_update_slab_size(sc_data_t *data, size_t begin, size_t end,
|
||||||
|
int pgs);
|
||||||
|
void sc_boot(sc_data_t *data);
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_INTERNAL_SC_H */
|
55
deps/jemalloc/include/jemalloc/internal/seq.h
vendored
Normal file
55
deps/jemalloc/include/jemalloc/internal/seq.h
vendored
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#ifndef JEMALLOC_INTERNAL_SEQ_H
|
||||||
|
#define JEMALLOC_INTERNAL_SEQ_H
|
||||||
|
|
||||||
|
#include "jemalloc/internal/atomic.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A simple seqlock implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define seq_define(type, short_type) \
|
||||||
|
typedef struct { \
|
||||||
|
atomic_zu_t seq; \
|
||||||
|
atomic_zu_t data[ \
|
||||||
|
(sizeof(type) + sizeof(size_t) - 1) / sizeof(size_t)]; \
|
||||||
|
} seq_##short_type##_t; \
|
||||||
|
\
|
||||||
|
/* \
|
||||||
|
* No internal synchronization -- the caller must ensure that there's \
|
||||||
|
* only a single writer at a time. \
|
||||||
|
*/ \
|
||||||
|
static inline void \
|
||||||
|
seq_store_##short_type(seq_##short_type##_t *dst, type *src) { \
|
||||||
|
size_t buf[sizeof(dst->data) / sizeof(size_t)]; \
|
||||||
|
buf[sizeof(buf) / sizeof(size_t) - 1] = 0; \
|
||||||
|
memcpy(buf, src, sizeof(type)); \
|
||||||
|
size_t old_seq = atomic_load_zu(&dst->seq, ATOMIC_RELAXED); \
|
||||||
|
atomic_store_zu(&dst->seq, old_seq + 1, ATOMIC_RELAXED); \
|
||||||
|
atomic_fence(ATOMIC_RELEASE); \
|
||||||
|
for (size_t i = 0; i < sizeof(buf) / sizeof(size_t); i++) { \
|
||||||
|
atomic_store_zu(&dst->data[i], buf[i], ATOMIC_RELAXED); \
|
||||||
|
} \
|
||||||
|
atomic_store_zu(&dst->seq, old_seq + 2, ATOMIC_RELEASE); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Returns whether or not the read was consistent. */ \
|
||||||
|
static inline bool \
|
||||||
|
seq_try_load_##short_type(type *dst, seq_##short_type##_t *src) { \
|
||||||
|
size_t buf[sizeof(src->data) / sizeof(size_t)]; \
|
||||||
|
size_t seq1 = atomic_load_zu(&src->seq, ATOMIC_ACQUIRE); \
|
||||||
|
if (seq1 % 2 != 0) { \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
for (size_t i = 0; i < sizeof(buf) / sizeof(size_t); i++) { \
|
||||||
|
buf[i] = atomic_load_zu(&src->data[i], ATOMIC_RELAXED); \
|
||||||
|
} \
|
||||||
|
atomic_fence(ATOMIC_ACQUIRE); \
|
||||||
|
size_t seq2 = atomic_load_zu(&src->seq, ATOMIC_RELAXED); \
|
||||||
|
if (seq1 != seq2) { \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
memcpy(dst, buf, sizeof(type)); \
|
||||||
|
return true; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_INTERNAL_SEQ_H */
|
@ -1,361 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
#
|
|
||||||
# Usage: size_classes.sh <lg_qarr> <lg_tmin> <lg_parr> <lg_g>
|
|
||||||
|
|
||||||
# The following limits are chosen such that they cover all supported platforms.
|
|
||||||
|
|
||||||
# Pointer sizes.
|
|
||||||
lg_zarr="2 3"
|
|
||||||
|
|
||||||
# Quanta.
|
|
||||||
lg_qarr=$1
|
|
||||||
|
|
||||||
# The range of tiny size classes is [2^lg_tmin..2^(lg_q-1)].
|
|
||||||
lg_tmin=$2
|
|
||||||
|
|
||||||
# Maximum lookup size.
|
|
||||||
lg_kmax=12
|
|
||||||
|
|
||||||
# Page sizes.
|
|
||||||
lg_parr=`echo $3 | tr ',' ' '`
|
|
||||||
|
|
||||||
# Size class group size (number of size classes for each size doubling).
|
|
||||||
lg_g=$4
|
|
||||||
|
|
||||||
pow2() {
|
|
||||||
e=$1
|
|
||||||
pow2_result=1
|
|
||||||
while [ ${e} -gt 0 ] ; do
|
|
||||||
pow2_result=$((${pow2_result} + ${pow2_result}))
|
|
||||||
e=$((${e} - 1))
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
lg() {
|
|
||||||
x=$1
|
|
||||||
lg_result=0
|
|
||||||
while [ ${x} -gt 1 ] ; do
|
|
||||||
lg_result=$((${lg_result} + 1))
|
|
||||||
x=$((${x} / 2))
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
lg_ceil() {
|
|
||||||
y=$1
|
|
||||||
lg ${y}; lg_floor=${lg_result}
|
|
||||||
pow2 ${lg_floor}; pow2_floor=${pow2_result}
|
|
||||||
if [ ${pow2_floor} -lt ${y} ] ; then
|
|
||||||
lg_ceil_result=$((${lg_floor} + 1))
|
|
||||||
else
|
|
||||||
lg_ceil_result=${lg_floor}
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
reg_size_compute() {
|
|
||||||
lg_grp=$1
|
|
||||||
lg_delta=$2
|
|
||||||
ndelta=$3
|
|
||||||
|
|
||||||
pow2 ${lg_grp}; grp=${pow2_result}
|
|
||||||
pow2 ${lg_delta}; delta=${pow2_result}
|
|
||||||
reg_size=$((${grp} + ${delta}*${ndelta}))
|
|
||||||
}
|
|
||||||
|
|
||||||
slab_size() {
|
|
||||||
lg_p=$1
|
|
||||||
lg_grp=$2
|
|
||||||
lg_delta=$3
|
|
||||||
ndelta=$4
|
|
||||||
|
|
||||||
pow2 ${lg_p}; p=${pow2_result}
|
|
||||||
reg_size_compute ${lg_grp} ${lg_delta} ${ndelta}
|
|
||||||
|
|
||||||
# Compute smallest slab size that is an integer multiple of reg_size.
|
|
||||||
try_slab_size=${p}
|
|
||||||
try_nregs=$((${try_slab_size} / ${reg_size}))
|
|
||||||
perfect=0
|
|
||||||
while [ ${perfect} -eq 0 ] ; do
|
|
||||||
perfect_slab_size=${try_slab_size}
|
|
||||||
perfect_nregs=${try_nregs}
|
|
||||||
|
|
||||||
try_slab_size=$((${try_slab_size} + ${p}))
|
|
||||||
try_nregs=$((${try_slab_size} / ${reg_size}))
|
|
||||||
if [ ${perfect_slab_size} -eq $((${perfect_nregs} * ${reg_size})) ] ; then
|
|
||||||
perfect=1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
slab_size_pgs=$((${perfect_slab_size} / ${p}))
|
|
||||||
}
|
|
||||||
|
|
||||||
size_class() {
|
|
||||||
index=$1
|
|
||||||
lg_grp=$2
|
|
||||||
lg_delta=$3
|
|
||||||
ndelta=$4
|
|
||||||
lg_p=$5
|
|
||||||
lg_kmax=$6
|
|
||||||
|
|
||||||
if [ ${lg_delta} -ge ${lg_p} ] ; then
|
|
||||||
psz="yes"
|
|
||||||
else
|
|
||||||
pow2 ${lg_p}; p=${pow2_result}
|
|
||||||
pow2 ${lg_grp}; grp=${pow2_result}
|
|
||||||
pow2 ${lg_delta}; delta=${pow2_result}
|
|
||||||
sz=$((${grp} + ${delta} * ${ndelta}))
|
|
||||||
npgs=$((${sz} / ${p}))
|
|
||||||
if [ ${sz} -eq $((${npgs} * ${p})) ] ; then
|
|
||||||
psz="yes"
|
|
||||||
else
|
|
||||||
psz="no"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
lg ${ndelta}; lg_ndelta=${lg_result}; pow2 ${lg_ndelta}
|
|
||||||
if [ ${pow2_result} -lt ${ndelta} ] ; then
|
|
||||||
rem="yes"
|
|
||||||
else
|
|
||||||
rem="no"
|
|
||||||
fi
|
|
||||||
|
|
||||||
lg_size=${lg_grp}
|
|
||||||
if [ $((${lg_delta} + ${lg_ndelta})) -eq ${lg_grp} ] ; then
|
|
||||||
lg_size=$((${lg_grp} + 1))
|
|
||||||
else
|
|
||||||
lg_size=${lg_grp}
|
|
||||||
rem="yes"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ${lg_size} -lt $((${lg_p} + ${lg_g})) ] ; then
|
|
||||||
bin="yes"
|
|
||||||
slab_size ${lg_p} ${lg_grp} ${lg_delta} ${ndelta}; pgs=${slab_size_pgs}
|
|
||||||
else
|
|
||||||
bin="no"
|
|
||||||
pgs=0
|
|
||||||
fi
|
|
||||||
if [ ${lg_size} -lt ${lg_kmax} \
|
|
||||||
-o ${lg_size} -eq ${lg_kmax} -a ${rem} = "no" ] ; then
|
|
||||||
lg_delta_lookup=${lg_delta}
|
|
||||||
else
|
|
||||||
lg_delta_lookup="no"
|
|
||||||
fi
|
|
||||||
printf ' SC(%3d, %6d, %8d, %6d, %3s, %3s, %3d, %2s) \\\n' ${index} ${lg_grp} ${lg_delta} ${ndelta} ${psz} ${bin} ${pgs} ${lg_delta_lookup}
|
|
||||||
# Defined upon return:
|
|
||||||
# - psz ("yes" or "no")
|
|
||||||
# - bin ("yes" or "no")
|
|
||||||
# - pgs
|
|
||||||
# - lg_delta_lookup (${lg_delta} or "no")
|
|
||||||
}
|
|
||||||
|
|
||||||
sep_line() {
|
|
||||||
echo " \\"
|
|
||||||
}
|
|
||||||
|
|
||||||
size_classes() {
|
|
||||||
lg_z=$1
|
|
||||||
lg_q=$2
|
|
||||||
lg_t=$3
|
|
||||||
lg_p=$4
|
|
||||||
lg_g=$5
|
|
||||||
|
|
||||||
pow2 $((${lg_z} + 3)); ptr_bits=${pow2_result}
|
|
||||||
pow2 ${lg_g}; g=${pow2_result}
|
|
||||||
|
|
||||||
echo "#define SIZE_CLASSES \\"
|
|
||||||
echo " /* index, lg_grp, lg_delta, ndelta, psz, bin, pgs, lg_delta_lookup */ \\"
|
|
||||||
|
|
||||||
ntbins=0
|
|
||||||
nlbins=0
|
|
||||||
lg_tiny_maxclass='"NA"'
|
|
||||||
nbins=0
|
|
||||||
npsizes=0
|
|
||||||
|
|
||||||
# Tiny size classes.
|
|
||||||
ndelta=0
|
|
||||||
index=0
|
|
||||||
lg_grp=${lg_t}
|
|
||||||
lg_delta=${lg_grp}
|
|
||||||
while [ ${lg_grp} -lt ${lg_q} ] ; do
|
|
||||||
size_class ${index} ${lg_grp} ${lg_delta} ${ndelta} ${lg_p} ${lg_kmax}
|
|
||||||
if [ ${lg_delta_lookup} != "no" ] ; then
|
|
||||||
nlbins=$((${index} + 1))
|
|
||||||
fi
|
|
||||||
if [ ${psz} = "yes" ] ; then
|
|
||||||
npsizes=$((${npsizes} + 1))
|
|
||||||
fi
|
|
||||||
if [ ${bin} != "no" ] ; then
|
|
||||||
nbins=$((${index} + 1))
|
|
||||||
fi
|
|
||||||
ntbins=$((${ntbins} + 1))
|
|
||||||
lg_tiny_maxclass=${lg_grp} # Final written value is correct.
|
|
||||||
index=$((${index} + 1))
|
|
||||||
lg_delta=${lg_grp}
|
|
||||||
lg_grp=$((${lg_grp} + 1))
|
|
||||||
done
|
|
||||||
|
|
||||||
# First non-tiny group.
|
|
||||||
if [ ${ntbins} -gt 0 ] ; then
|
|
||||||
sep_line
|
|
||||||
# The first size class has an unusual encoding, because the size has to be
|
|
||||||
# split between grp and delta*ndelta.
|
|
||||||
lg_grp=$((${lg_grp} - 1))
|
|
||||||
ndelta=1
|
|
||||||
size_class ${index} ${lg_grp} ${lg_delta} ${ndelta} ${lg_p} ${lg_kmax}
|
|
||||||
index=$((${index} + 1))
|
|
||||||
lg_grp=$((${lg_grp} + 1))
|
|
||||||
lg_delta=$((${lg_delta} + 1))
|
|
||||||
if [ ${psz} = "yes" ] ; then
|
|
||||||
npsizes=$((${npsizes} + 1))
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
while [ ${ndelta} -lt ${g} ] ; do
|
|
||||||
size_class ${index} ${lg_grp} ${lg_delta} ${ndelta} ${lg_p} ${lg_kmax}
|
|
||||||
index=$((${index} + 1))
|
|
||||||
ndelta=$((${ndelta} + 1))
|
|
||||||
if [ ${psz} = "yes" ] ; then
|
|
||||||
npsizes=$((${npsizes} + 1))
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# All remaining groups.
|
|
||||||
lg_grp=$((${lg_grp} + ${lg_g}))
|
|
||||||
while [ ${lg_grp} -lt $((${ptr_bits} - 1)) ] ; do
|
|
||||||
sep_line
|
|
||||||
ndelta=1
|
|
||||||
if [ ${lg_grp} -eq $((${ptr_bits} - 2)) ] ; then
|
|
||||||
ndelta_limit=$((${g} - 1))
|
|
||||||
else
|
|
||||||
ndelta_limit=${g}
|
|
||||||
fi
|
|
||||||
while [ ${ndelta} -le ${ndelta_limit} ] ; do
|
|
||||||
size_class ${index} ${lg_grp} ${lg_delta} ${ndelta} ${lg_p} ${lg_kmax}
|
|
||||||
if [ ${lg_delta_lookup} != "no" ] ; then
|
|
||||||
nlbins=$((${index} + 1))
|
|
||||||
# Final written value is correct:
|
|
||||||
lookup_maxclass="((((size_t)1) << ${lg_grp}) + (((size_t)${ndelta}) << ${lg_delta}))"
|
|
||||||
fi
|
|
||||||
if [ ${psz} = "yes" ] ; then
|
|
||||||
npsizes=$((${npsizes} + 1))
|
|
||||||
fi
|
|
||||||
if [ ${bin} != "no" ] ; then
|
|
||||||
nbins=$((${index} + 1))
|
|
||||||
# Final written value is correct:
|
|
||||||
small_maxclass="((((size_t)1) << ${lg_grp}) + (((size_t)${ndelta}) << ${lg_delta}))"
|
|
||||||
if [ ${lg_g} -gt 0 ] ; then
|
|
||||||
lg_large_minclass=$((${lg_grp} + 1))
|
|
||||||
else
|
|
||||||
lg_large_minclass=$((${lg_grp} + 2))
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
# Final written value is correct:
|
|
||||||
large_maxclass="((((size_t)1) << ${lg_grp}) + (((size_t)${ndelta}) << ${lg_delta}))"
|
|
||||||
index=$((${index} + 1))
|
|
||||||
ndelta=$((${ndelta} + 1))
|
|
||||||
done
|
|
||||||
lg_grp=$((${lg_grp} + 1))
|
|
||||||
lg_delta=$((${lg_delta} + 1))
|
|
||||||
done
|
|
||||||
echo
|
|
||||||
nsizes=${index}
|
|
||||||
lg_ceil ${nsizes}; lg_ceil_nsizes=${lg_ceil_result}
|
|
||||||
|
|
||||||
# Defined upon completion:
|
|
||||||
# - ntbins
|
|
||||||
# - nlbins
|
|
||||||
# - nbins
|
|
||||||
# - nsizes
|
|
||||||
# - lg_ceil_nsizes
|
|
||||||
# - npsizes
|
|
||||||
# - lg_tiny_maxclass
|
|
||||||
# - lookup_maxclass
|
|
||||||
# - small_maxclass
|
|
||||||
# - lg_large_minclass
|
|
||||||
# - large_maxclass
|
|
||||||
}
|
|
||||||
|
|
||||||
cat <<EOF
|
|
||||||
#ifndef JEMALLOC_INTERNAL_SIZE_CLASSES_H
|
|
||||||
#define JEMALLOC_INTERNAL_SIZE_CLASSES_H
|
|
||||||
|
|
||||||
/* This file was automatically generated by size_classes.sh. */
|
|
||||||
|
|
||||||
#include "jemalloc/internal/jemalloc_internal_types.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This header file defines:
|
|
||||||
*
|
|
||||||
* LG_SIZE_CLASS_GROUP: Lg of size class count for each size doubling.
|
|
||||||
* LG_TINY_MIN: Lg of minimum size class to support.
|
|
||||||
* SIZE_CLASSES: Complete table of SC(index, lg_grp, lg_delta, ndelta, psz,
|
|
||||||
* bin, pgs, lg_delta_lookup) tuples.
|
|
||||||
* index: Size class index.
|
|
||||||
* lg_grp: Lg group base size (no deltas added).
|
|
||||||
* lg_delta: Lg delta to previous size class.
|
|
||||||
* ndelta: Delta multiplier. size == 1<<lg_grp + ndelta<<lg_delta
|
|
||||||
* psz: 'yes' if a multiple of the page size, 'no' otherwise.
|
|
||||||
* bin: 'yes' if a small bin size class, 'no' otherwise.
|
|
||||||
* pgs: Slab page count if a small bin size class, 0 otherwise.
|
|
||||||
* lg_delta_lookup: Same as lg_delta if a lookup table size class, 'no'
|
|
||||||
* otherwise.
|
|
||||||
* NTBINS: Number of tiny bins.
|
|
||||||
* NLBINS: Number of bins supported by the lookup table.
|
|
||||||
* NBINS: Number of small size class bins.
|
|
||||||
* NSIZES: Number of size classes.
|
|
||||||
* LG_CEIL_NSIZES: Number of bits required to store NSIZES.
|
|
||||||
* NPSIZES: Number of size classes that are a multiple of (1U << LG_PAGE).
|
|
||||||
* LG_TINY_MAXCLASS: Lg of maximum tiny size class.
|
|
||||||
* LOOKUP_MAXCLASS: Maximum size class included in lookup table.
|
|
||||||
* SMALL_MAXCLASS: Maximum small size class.
|
|
||||||
* LG_LARGE_MINCLASS: Lg of minimum large size class.
|
|
||||||
* LARGE_MAXCLASS: Maximum (large) size class.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define LG_SIZE_CLASS_GROUP ${lg_g}
|
|
||||||
#define LG_TINY_MIN ${lg_tmin}
|
|
||||||
|
|
||||||
EOF
|
|
||||||
|
|
||||||
for lg_z in ${lg_zarr} ; do
|
|
||||||
for lg_q in ${lg_qarr} ; do
|
|
||||||
lg_t=${lg_tmin}
|
|
||||||
while [ ${lg_t} -le ${lg_q} ] ; do
|
|
||||||
# Iterate through page sizes and compute how many bins there are.
|
|
||||||
for lg_p in ${lg_parr} ; do
|
|
||||||
echo "#if (LG_SIZEOF_PTR == ${lg_z} && LG_TINY_MIN == ${lg_t} && LG_QUANTUM == ${lg_q} && LG_PAGE == ${lg_p})"
|
|
||||||
size_classes ${lg_z} ${lg_q} ${lg_t} ${lg_p} ${lg_g}
|
|
||||||
echo "#define SIZE_CLASSES_DEFINED"
|
|
||||||
echo "#define NTBINS ${ntbins}"
|
|
||||||
echo "#define NLBINS ${nlbins}"
|
|
||||||
echo "#define NBINS ${nbins}"
|
|
||||||
echo "#define NSIZES ${nsizes}"
|
|
||||||
echo "#define LG_CEIL_NSIZES ${lg_ceil_nsizes}"
|
|
||||||
echo "#define NPSIZES ${npsizes}"
|
|
||||||
echo "#define LG_TINY_MAXCLASS ${lg_tiny_maxclass}"
|
|
||||||
echo "#define LOOKUP_MAXCLASS ${lookup_maxclass}"
|
|
||||||
echo "#define SMALL_MAXCLASS ${small_maxclass}"
|
|
||||||
echo "#define LG_LARGE_MINCLASS ${lg_large_minclass}"
|
|
||||||
echo "#define LARGE_MINCLASS (ZU(1) << LG_LARGE_MINCLASS)"
|
|
||||||
echo "#define LARGE_MAXCLASS ${large_maxclass}"
|
|
||||||
echo "#endif"
|
|
||||||
echo
|
|
||||||
done
|
|
||||||
lg_t=$((${lg_t} + 1))
|
|
||||||
done
|
|
||||||
done
|
|
||||||
done
|
|
||||||
|
|
||||||
cat <<EOF
|
|
||||||
#ifndef SIZE_CLASSES_DEFINED
|
|
||||||
# error "No size class definitions match configuration"
|
|
||||||
#endif
|
|
||||||
#undef SIZE_CLASSES_DEFINED
|
|
||||||
/*
|
|
||||||
* The size2index_tab lookup table uses uint8_t to encode each bin index, so we
|
|
||||||
* cannot support more than 256 small size classes.
|
|
||||||
*/
|
|
||||||
#if (NBINS > 256)
|
|
||||||
# error "Too many small size classes"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_SIZE_CLASSES_H */
|
|
||||||
EOF
|
|
@ -10,7 +10,8 @@
|
|||||||
OPTION('a', unmerged, config_stats, false) \
|
OPTION('a', unmerged, config_stats, false) \
|
||||||
OPTION('b', bins, true, false) \
|
OPTION('b', bins, true, false) \
|
||||||
OPTION('l', large, true, false) \
|
OPTION('l', large, true, false) \
|
||||||
OPTION('x', mutex, true, false)
|
OPTION('x', mutex, true, false) \
|
||||||
|
OPTION('e', extents, true, false)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
#define OPTION(o, v, d, s) stats_print_option_num_##v,
|
#define OPTION(o, v, d, s) stats_print_option_num_##v,
|
||||||
|
137
deps/jemalloc/include/jemalloc/internal/sz.h
vendored
137
deps/jemalloc/include/jemalloc/internal/sz.h
vendored
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "jemalloc/internal/bit_util.h"
|
#include "jemalloc/internal/bit_util.h"
|
||||||
#include "jemalloc/internal/pages.h"
|
#include "jemalloc/internal/pages.h"
|
||||||
#include "jemalloc/internal/size_classes.h"
|
#include "jemalloc/internal/sc.h"
|
||||||
#include "jemalloc/internal/util.h"
|
#include "jemalloc/internal/util.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -26,18 +26,18 @@
|
|||||||
* sz_pind2sz_tab encodes the same information as could be computed by
|
* sz_pind2sz_tab encodes the same information as could be computed by
|
||||||
* sz_pind2sz_compute().
|
* sz_pind2sz_compute().
|
||||||
*/
|
*/
|
||||||
extern size_t const sz_pind2sz_tab[NPSIZES+1];
|
extern size_t sz_pind2sz_tab[SC_NPSIZES + 1];
|
||||||
/*
|
/*
|
||||||
* sz_index2size_tab encodes the same information as could be computed (at
|
* sz_index2size_tab encodes the same information as could be computed (at
|
||||||
* unacceptable cost in some code paths) by sz_index2size_compute().
|
* unacceptable cost in some code paths) by sz_index2size_compute().
|
||||||
*/
|
*/
|
||||||
extern size_t const sz_index2size_tab[NSIZES];
|
extern size_t sz_index2size_tab[SC_NSIZES];
|
||||||
/*
|
/*
|
||||||
* sz_size2index_tab is a compact lookup table that rounds request sizes up to
|
* sz_size2index_tab is a compact lookup table that rounds request sizes up to
|
||||||
* size classes. In order to reduce cache footprint, the table is compressed,
|
* size classes. In order to reduce cache footprint, the table is compressed,
|
||||||
* and all accesses are via sz_size2index().
|
* and all accesses are via sz_size2index().
|
||||||
*/
|
*/
|
||||||
extern uint8_t const sz_size2index_tab[];
|
extern uint8_t sz_size2index_tab[];
|
||||||
|
|
||||||
static const size_t sz_large_pad =
|
static const size_t sz_large_pad =
|
||||||
#ifdef JEMALLOC_CACHE_OBLIVIOUS
|
#ifdef JEMALLOC_CACHE_OBLIVIOUS
|
||||||
@ -47,41 +47,40 @@ static const size_t sz_large_pad =
|
|||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
|
extern void sz_boot(const sc_data_t *sc_data);
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE pszind_t
|
JEMALLOC_ALWAYS_INLINE pszind_t
|
||||||
sz_psz2ind(size_t psz) {
|
sz_psz2ind(size_t psz) {
|
||||||
if (unlikely(psz > LARGE_MAXCLASS)) {
|
if (unlikely(psz > SC_LARGE_MAXCLASS)) {
|
||||||
return NPSIZES;
|
return SC_NPSIZES;
|
||||||
}
|
}
|
||||||
{
|
|
||||||
pszind_t x = lg_floor((psz<<1)-1);
|
pszind_t x = lg_floor((psz<<1)-1);
|
||||||
pszind_t shift = (x < LG_SIZE_CLASS_GROUP + LG_PAGE) ? 0 : x -
|
pszind_t shift = (x < SC_LG_NGROUP + LG_PAGE) ?
|
||||||
(LG_SIZE_CLASS_GROUP + LG_PAGE);
|
0 : x - (SC_LG_NGROUP + LG_PAGE);
|
||||||
pszind_t grp = shift << LG_SIZE_CLASS_GROUP;
|
pszind_t grp = shift << SC_LG_NGROUP;
|
||||||
|
|
||||||
pszind_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_PAGE + 1) ?
|
pszind_t lg_delta = (x < SC_LG_NGROUP + LG_PAGE + 1) ?
|
||||||
LG_PAGE : x - LG_SIZE_CLASS_GROUP - 1;
|
LG_PAGE : x - SC_LG_NGROUP - 1;
|
||||||
|
|
||||||
size_t delta_inverse_mask = ZU(-1) << lg_delta;
|
size_t delta_inverse_mask = ZU(-1) << lg_delta;
|
||||||
pszind_t mod = ((((psz-1) & delta_inverse_mask) >> lg_delta)) &
|
pszind_t mod = ((((psz-1) & delta_inverse_mask) >> lg_delta)) &
|
||||||
((ZU(1) << LG_SIZE_CLASS_GROUP) - 1);
|
((ZU(1) << SC_LG_NGROUP) - 1);
|
||||||
|
|
||||||
pszind_t ind = grp + mod;
|
pszind_t ind = grp + mod;
|
||||||
return ind;
|
return ind;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static inline size_t
|
static inline size_t
|
||||||
sz_pind2sz_compute(pszind_t pind) {
|
sz_pind2sz_compute(pszind_t pind) {
|
||||||
if (unlikely(pind == NPSIZES)) {
|
if (unlikely(pind == SC_NPSIZES)) {
|
||||||
return LARGE_MAXCLASS + PAGE;
|
return SC_LARGE_MAXCLASS + PAGE;
|
||||||
}
|
}
|
||||||
{
|
size_t grp = pind >> SC_LG_NGROUP;
|
||||||
size_t grp = pind >> LG_SIZE_CLASS_GROUP;
|
size_t mod = pind & ((ZU(1) << SC_LG_NGROUP) - 1);
|
||||||
size_t mod = pind & ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1);
|
|
||||||
|
|
||||||
size_t grp_size_mask = ~((!!grp)-1);
|
size_t grp_size_mask = ~((!!grp)-1);
|
||||||
size_t grp_size = ((ZU(1) << (LG_PAGE +
|
size_t grp_size = ((ZU(1) << (LG_PAGE + (SC_LG_NGROUP-1))) << grp)
|
||||||
(LG_SIZE_CLASS_GROUP-1))) << grp) & grp_size_mask;
|
& grp_size_mask;
|
||||||
|
|
||||||
size_t shift = (grp == 0) ? 1 : grp;
|
size_t shift = (grp == 0) ? 1 : grp;
|
||||||
size_t lg_delta = shift + (LG_PAGE-1);
|
size_t lg_delta = shift + (LG_PAGE-1);
|
||||||
@ -90,7 +89,6 @@ sz_pind2sz_compute(pszind_t pind) {
|
|||||||
size_t sz = grp_size + mod_size;
|
size_t sz = grp_size + mod_size;
|
||||||
return sz;
|
return sz;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static inline size_t
|
static inline size_t
|
||||||
sz_pind2sz_lookup(pszind_t pind) {
|
sz_pind2sz_lookup(pszind_t pind) {
|
||||||
@ -101,70 +99,70 @@ sz_pind2sz_lookup(pszind_t pind) {
|
|||||||
|
|
||||||
static inline size_t
|
static inline size_t
|
||||||
sz_pind2sz(pszind_t pind) {
|
sz_pind2sz(pszind_t pind) {
|
||||||
assert(pind < NPSIZES+1);
|
assert(pind < SC_NPSIZES + 1);
|
||||||
return sz_pind2sz_lookup(pind);
|
return sz_pind2sz_lookup(pind);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline size_t
|
static inline size_t
|
||||||
sz_psz2u(size_t psz) {
|
sz_psz2u(size_t psz) {
|
||||||
if (unlikely(psz > LARGE_MAXCLASS)) {
|
if (unlikely(psz > SC_LARGE_MAXCLASS)) {
|
||||||
return LARGE_MAXCLASS + PAGE;
|
return SC_LARGE_MAXCLASS + PAGE;
|
||||||
}
|
}
|
||||||
{
|
|
||||||
size_t x = lg_floor((psz<<1)-1);
|
size_t x = lg_floor((psz<<1)-1);
|
||||||
size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_PAGE + 1) ?
|
size_t lg_delta = (x < SC_LG_NGROUP + LG_PAGE + 1) ?
|
||||||
LG_PAGE : x - LG_SIZE_CLASS_GROUP - 1;
|
LG_PAGE : x - SC_LG_NGROUP - 1;
|
||||||
size_t delta = ZU(1) << lg_delta;
|
size_t delta = ZU(1) << lg_delta;
|
||||||
size_t delta_mask = delta - 1;
|
size_t delta_mask = delta - 1;
|
||||||
size_t usize = (psz + delta_mask) & ~delta_mask;
|
size_t usize = (psz + delta_mask) & ~delta_mask;
|
||||||
return usize;
|
return usize;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static inline szind_t
|
static inline szind_t
|
||||||
sz_size2index_compute(size_t size) {
|
sz_size2index_compute(size_t size) {
|
||||||
if (unlikely(size > LARGE_MAXCLASS)) {
|
if (unlikely(size > SC_LARGE_MAXCLASS)) {
|
||||||
return NSIZES;
|
return SC_NSIZES;
|
||||||
}
|
}
|
||||||
#if (NTBINS != 0)
|
|
||||||
if (size <= (ZU(1) << LG_TINY_MAXCLASS)) {
|
if (size == 0) {
|
||||||
szind_t lg_tmin = LG_TINY_MAXCLASS - NTBINS + 1;
|
return 0;
|
||||||
|
}
|
||||||
|
#if (SC_NTINY != 0)
|
||||||
|
if (size <= (ZU(1) << SC_LG_TINY_MAXCLASS)) {
|
||||||
|
szind_t lg_tmin = SC_LG_TINY_MAXCLASS - SC_NTINY + 1;
|
||||||
szind_t lg_ceil = lg_floor(pow2_ceil_zu(size));
|
szind_t lg_ceil = lg_floor(pow2_ceil_zu(size));
|
||||||
return (lg_ceil < lg_tmin ? 0 : lg_ceil - lg_tmin);
|
return (lg_ceil < lg_tmin ? 0 : lg_ceil - lg_tmin);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
szind_t x = lg_floor((size<<1)-1);
|
szind_t x = lg_floor((size<<1)-1);
|
||||||
szind_t shift = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM) ? 0 :
|
szind_t shift = (x < SC_LG_NGROUP + LG_QUANTUM) ? 0 :
|
||||||
x - (LG_SIZE_CLASS_GROUP + LG_QUANTUM);
|
x - (SC_LG_NGROUP + LG_QUANTUM);
|
||||||
szind_t grp = shift << LG_SIZE_CLASS_GROUP;
|
szind_t grp = shift << SC_LG_NGROUP;
|
||||||
|
|
||||||
szind_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM + 1)
|
szind_t lg_delta = (x < SC_LG_NGROUP + LG_QUANTUM + 1)
|
||||||
? LG_QUANTUM : x - LG_SIZE_CLASS_GROUP - 1;
|
? LG_QUANTUM : x - SC_LG_NGROUP - 1;
|
||||||
|
|
||||||
size_t delta_inverse_mask = ZU(-1) << lg_delta;
|
size_t delta_inverse_mask = ZU(-1) << lg_delta;
|
||||||
szind_t mod = ((((size-1) & delta_inverse_mask) >> lg_delta)) &
|
szind_t mod = ((((size-1) & delta_inverse_mask) >> lg_delta)) &
|
||||||
((ZU(1) << LG_SIZE_CLASS_GROUP) - 1);
|
((ZU(1) << SC_LG_NGROUP) - 1);
|
||||||
|
|
||||||
szind_t index = NTBINS + grp + mod;
|
szind_t index = SC_NTINY + grp + mod;
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE szind_t
|
JEMALLOC_ALWAYS_INLINE szind_t
|
||||||
sz_size2index_lookup(size_t size) {
|
sz_size2index_lookup(size_t size) {
|
||||||
assert(size <= LOOKUP_MAXCLASS);
|
assert(size <= SC_LOOKUP_MAXCLASS);
|
||||||
{
|
szind_t ret = (sz_size2index_tab[(size + (ZU(1) << SC_LG_TINY_MIN) - 1)
|
||||||
szind_t ret = (sz_size2index_tab[(size-1) >> LG_TINY_MIN]);
|
>> SC_LG_TINY_MIN]);
|
||||||
assert(ret == sz_size2index_compute(size));
|
assert(ret == sz_size2index_compute(size));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE szind_t
|
JEMALLOC_ALWAYS_INLINE szind_t
|
||||||
sz_size2index(size_t size) {
|
sz_size2index(size_t size) {
|
||||||
assert(size > 0);
|
if (likely(size <= SC_LOOKUP_MAXCLASS)) {
|
||||||
if (likely(size <= LOOKUP_MAXCLASS)) {
|
|
||||||
return sz_size2index_lookup(size);
|
return sz_size2index_lookup(size);
|
||||||
}
|
}
|
||||||
return sz_size2index_compute(size);
|
return sz_size2index_compute(size);
|
||||||
@ -172,20 +170,20 @@ sz_size2index(size_t size) {
|
|||||||
|
|
||||||
static inline size_t
|
static inline size_t
|
||||||
sz_index2size_compute(szind_t index) {
|
sz_index2size_compute(szind_t index) {
|
||||||
#if (NTBINS > 0)
|
#if (SC_NTINY > 0)
|
||||||
if (index < NTBINS) {
|
if (index < SC_NTINY) {
|
||||||
return (ZU(1) << (LG_TINY_MAXCLASS - NTBINS + 1 + index));
|
return (ZU(1) << (SC_LG_TINY_MAXCLASS - SC_NTINY + 1 + index));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
size_t reduced_index = index - NTBINS;
|
size_t reduced_index = index - SC_NTINY;
|
||||||
size_t grp = reduced_index >> LG_SIZE_CLASS_GROUP;
|
size_t grp = reduced_index >> SC_LG_NGROUP;
|
||||||
size_t mod = reduced_index & ((ZU(1) << LG_SIZE_CLASS_GROUP) -
|
size_t mod = reduced_index & ((ZU(1) << SC_LG_NGROUP) -
|
||||||
1);
|
1);
|
||||||
|
|
||||||
size_t grp_size_mask = ~((!!grp)-1);
|
size_t grp_size_mask = ~((!!grp)-1);
|
||||||
size_t grp_size = ((ZU(1) << (LG_QUANTUM +
|
size_t grp_size = ((ZU(1) << (LG_QUANTUM +
|
||||||
(LG_SIZE_CLASS_GROUP-1))) << grp) & grp_size_mask;
|
(SC_LG_NGROUP-1))) << grp) & grp_size_mask;
|
||||||
|
|
||||||
size_t shift = (grp == 0) ? 1 : grp;
|
size_t shift = (grp == 0) ? 1 : grp;
|
||||||
size_t lg_delta = shift + (LG_QUANTUM-1);
|
size_t lg_delta = shift + (LG_QUANTUM-1);
|
||||||
@ -205,18 +203,22 @@ sz_index2size_lookup(szind_t index) {
|
|||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE size_t
|
JEMALLOC_ALWAYS_INLINE size_t
|
||||||
sz_index2size(szind_t index) {
|
sz_index2size(szind_t index) {
|
||||||
assert(index < NSIZES);
|
assert(index < SC_NSIZES);
|
||||||
return sz_index2size_lookup(index);
|
return sz_index2size_lookup(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE size_t
|
JEMALLOC_ALWAYS_INLINE size_t
|
||||||
sz_s2u_compute(size_t size) {
|
sz_s2u_compute(size_t size) {
|
||||||
if (unlikely(size > LARGE_MAXCLASS)) {
|
if (unlikely(size > SC_LARGE_MAXCLASS)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#if (NTBINS > 0)
|
|
||||||
if (size <= (ZU(1) << LG_TINY_MAXCLASS)) {
|
if (size == 0) {
|
||||||
size_t lg_tmin = LG_TINY_MAXCLASS - NTBINS + 1;
|
size++;
|
||||||
|
}
|
||||||
|
#if (SC_NTINY > 0)
|
||||||
|
if (size <= (ZU(1) << SC_LG_TINY_MAXCLASS)) {
|
||||||
|
size_t lg_tmin = SC_LG_TINY_MAXCLASS - SC_NTINY + 1;
|
||||||
size_t lg_ceil = lg_floor(pow2_ceil_zu(size));
|
size_t lg_ceil = lg_floor(pow2_ceil_zu(size));
|
||||||
return (lg_ceil < lg_tmin ? (ZU(1) << lg_tmin) :
|
return (lg_ceil < lg_tmin ? (ZU(1) << lg_tmin) :
|
||||||
(ZU(1) << lg_ceil));
|
(ZU(1) << lg_ceil));
|
||||||
@ -224,8 +226,8 @@ sz_s2u_compute(size_t size) {
|
|||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
size_t x = lg_floor((size<<1)-1);
|
size_t x = lg_floor((size<<1)-1);
|
||||||
size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM + 1)
|
size_t lg_delta = (x < SC_LG_NGROUP + LG_QUANTUM + 1)
|
||||||
? LG_QUANTUM : x - LG_SIZE_CLASS_GROUP - 1;
|
? LG_QUANTUM : x - SC_LG_NGROUP - 1;
|
||||||
size_t delta = ZU(1) << lg_delta;
|
size_t delta = ZU(1) << lg_delta;
|
||||||
size_t delta_mask = delta - 1;
|
size_t delta_mask = delta - 1;
|
||||||
size_t usize = (size + delta_mask) & ~delta_mask;
|
size_t usize = (size + delta_mask) & ~delta_mask;
|
||||||
@ -247,8 +249,7 @@ sz_s2u_lookup(size_t size) {
|
|||||||
*/
|
*/
|
||||||
JEMALLOC_ALWAYS_INLINE size_t
|
JEMALLOC_ALWAYS_INLINE size_t
|
||||||
sz_s2u(size_t size) {
|
sz_s2u(size_t size) {
|
||||||
assert(size > 0);
|
if (likely(size <= SC_LOOKUP_MAXCLASS)) {
|
||||||
if (likely(size <= LOOKUP_MAXCLASS)) {
|
|
||||||
return sz_s2u_lookup(size);
|
return sz_s2u_lookup(size);
|
||||||
}
|
}
|
||||||
return sz_s2u_compute(size);
|
return sz_s2u_compute(size);
|
||||||
@ -265,7 +266,7 @@ sz_sa2u(size_t size, size_t alignment) {
|
|||||||
assert(alignment != 0 && ((alignment - 1) & alignment) == 0);
|
assert(alignment != 0 && ((alignment - 1) & alignment) == 0);
|
||||||
|
|
||||||
/* Try for a small size class. */
|
/* Try for a small size class. */
|
||||||
if (size <= SMALL_MAXCLASS && alignment < PAGE) {
|
if (size <= SC_SMALL_MAXCLASS && alignment < PAGE) {
|
||||||
/*
|
/*
|
||||||
* Round size up to the nearest multiple of alignment.
|
* Round size up to the nearest multiple of alignment.
|
||||||
*
|
*
|
||||||
@ -281,20 +282,20 @@ sz_sa2u(size_t size, size_t alignment) {
|
|||||||
* 192 | 11000000 | 64
|
* 192 | 11000000 | 64
|
||||||
*/
|
*/
|
||||||
usize = sz_s2u(ALIGNMENT_CEILING(size, alignment));
|
usize = sz_s2u(ALIGNMENT_CEILING(size, alignment));
|
||||||
if (usize < LARGE_MINCLASS) {
|
if (usize < SC_LARGE_MINCLASS) {
|
||||||
return usize;
|
return usize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Large size class. Beware of overflow. */
|
/* Large size class. Beware of overflow. */
|
||||||
|
|
||||||
if (unlikely(alignment > LARGE_MAXCLASS)) {
|
if (unlikely(alignment > SC_LARGE_MAXCLASS)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure result is a large size class. */
|
/* Make sure result is a large size class. */
|
||||||
if (size <= LARGE_MINCLASS) {
|
if (size <= SC_LARGE_MINCLASS) {
|
||||||
usize = LARGE_MINCLASS;
|
usize = SC_LARGE_MINCLASS;
|
||||||
} else {
|
} else {
|
||||||
usize = sz_s2u(size);
|
usize = sz_s2u(size);
|
||||||
if (usize < size) {
|
if (usize < size) {
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
#ifndef JEMALLOC_INTERNAL_TCACHE_EXTERNS_H
|
#ifndef JEMALLOC_INTERNAL_TCACHE_EXTERNS_H
|
||||||
#define JEMALLOC_INTERNAL_TCACHE_EXTERNS_H
|
#define JEMALLOC_INTERNAL_TCACHE_EXTERNS_H
|
||||||
|
|
||||||
#include "jemalloc/internal/size_classes.h"
|
|
||||||
|
|
||||||
extern bool opt_tcache;
|
extern bool opt_tcache;
|
||||||
extern ssize_t opt_lg_tcache_max;
|
extern ssize_t opt_lg_tcache_max;
|
||||||
|
|
||||||
extern cache_bin_info_t *tcache_bin_info;
|
extern cache_bin_info_t *tcache_bin_info;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Number of tcache bins. There are NBINS small-object bins, plus 0 or more
|
* Number of tcache bins. There are SC_NBINS small-object bins, plus 0 or more
|
||||||
* large-object bins.
|
* large-object bins.
|
||||||
*/
|
*/
|
||||||
extern unsigned nhbins;
|
extern unsigned nhbins;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "jemalloc/internal/bin.h"
|
#include "jemalloc/internal/bin.h"
|
||||||
#include "jemalloc/internal/jemalloc_internal_types.h"
|
#include "jemalloc/internal/jemalloc_internal_types.h"
|
||||||
#include "jemalloc/internal/size_classes.h"
|
#include "jemalloc/internal/sc.h"
|
||||||
#include "jemalloc/internal/sz.h"
|
#include "jemalloc/internal/sz.h"
|
||||||
#include "jemalloc/internal/ticker.h"
|
#include "jemalloc/internal/ticker.h"
|
||||||
#include "jemalloc/internal/util.h"
|
#include "jemalloc/internal/util.h"
|
||||||
@ -40,13 +40,13 @@ tcache_event(tsd_t *tsd, tcache_t *tcache) {
|
|||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void *
|
JEMALLOC_ALWAYS_INLINE void *
|
||||||
tcache_alloc_small(tsd_t *tsd, arena_t *arena, tcache_t *tcache,
|
tcache_alloc_small(tsd_t *tsd, arena_t *arena, tcache_t *tcache,
|
||||||
UNUSED size_t size, szind_t binind, bool zero, bool slow_path) {
|
size_t size, szind_t binind, bool zero, bool slow_path) {
|
||||||
void *ret;
|
void *ret;
|
||||||
cache_bin_t *bin;
|
cache_bin_t *bin;
|
||||||
bool tcache_success;
|
bool tcache_success;
|
||||||
size_t usize JEMALLOC_CC_SILENCE_INIT(0);
|
size_t usize JEMALLOC_CC_SILENCE_INIT(0);
|
||||||
|
|
||||||
assert(binind < NBINS);
|
assert(binind < SC_NBINS);
|
||||||
bin = tcache_small_bin_get(tcache, binind);
|
bin = tcache_small_bin_get(tcache, binind);
|
||||||
ret = cache_bin_alloc_easy(bin, &tcache_success);
|
ret = cache_bin_alloc_easy(bin, &tcache_success);
|
||||||
assert(tcache_success == (ret != NULL));
|
assert(tcache_success == (ret != NULL));
|
||||||
@ -107,7 +107,7 @@ tcache_alloc_large(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size,
|
|||||||
cache_bin_t *bin;
|
cache_bin_t *bin;
|
||||||
bool tcache_success;
|
bool tcache_success;
|
||||||
|
|
||||||
assert(binind >= NBINS &&binind < nhbins);
|
assert(binind >= SC_NBINS &&binind < nhbins);
|
||||||
bin = tcache_large_bin_get(tcache, binind);
|
bin = tcache_large_bin_get(tcache, binind);
|
||||||
ret = cache_bin_alloc_easy(bin, &tcache_success);
|
ret = cache_bin_alloc_easy(bin, &tcache_success);
|
||||||
assert(tcache_success == (ret != NULL));
|
assert(tcache_success == (ret != NULL));
|
||||||
@ -166,7 +166,8 @@ tcache_dalloc_small(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind,
|
|||||||
cache_bin_t *bin;
|
cache_bin_t *bin;
|
||||||
cache_bin_info_t *bin_info;
|
cache_bin_info_t *bin_info;
|
||||||
|
|
||||||
assert(tcache_salloc(tsd_tsdn(tsd), ptr) <= SMALL_MAXCLASS);
|
assert(tcache_salloc(tsd_tsdn(tsd), ptr)
|
||||||
|
<= SC_SMALL_MAXCLASS);
|
||||||
|
|
||||||
if (slow_path && config_fill && unlikely(opt_junk_free)) {
|
if (slow_path && config_fill && unlikely(opt_junk_free)) {
|
||||||
arena_dalloc_junk_small(ptr, &bin_infos[binind]);
|
arena_dalloc_junk_small(ptr, &bin_infos[binind]);
|
||||||
@ -174,13 +175,12 @@ tcache_dalloc_small(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind,
|
|||||||
|
|
||||||
bin = tcache_small_bin_get(tcache, binind);
|
bin = tcache_small_bin_get(tcache, binind);
|
||||||
bin_info = &tcache_bin_info[binind];
|
bin_info = &tcache_bin_info[binind];
|
||||||
if (unlikely(bin->ncached == bin_info->ncached_max)) {
|
if (unlikely(!cache_bin_dalloc_easy(bin, bin_info, ptr))) {
|
||||||
tcache_bin_flush_small(tsd, tcache, bin, binind,
|
tcache_bin_flush_small(tsd, tcache, bin, binind,
|
||||||
(bin_info->ncached_max >> 1));
|
(bin_info->ncached_max >> 1));
|
||||||
|
bool ret = cache_bin_dalloc_easy(bin, bin_info, ptr);
|
||||||
|
assert(ret);
|
||||||
}
|
}
|
||||||
assert(bin->ncached < bin_info->ncached_max);
|
|
||||||
bin->ncached++;
|
|
||||||
*(bin->avail - bin->ncached) = ptr;
|
|
||||||
|
|
||||||
tcache_event(tsd, tcache);
|
tcache_event(tsd, tcache);
|
||||||
}
|
}
|
||||||
@ -191,7 +191,8 @@ tcache_dalloc_large(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind,
|
|||||||
cache_bin_t *bin;
|
cache_bin_t *bin;
|
||||||
cache_bin_info_t *bin_info;
|
cache_bin_info_t *bin_info;
|
||||||
|
|
||||||
assert(tcache_salloc(tsd_tsdn(tsd), ptr) > SMALL_MAXCLASS);
|
assert(tcache_salloc(tsd_tsdn(tsd), ptr)
|
||||||
|
> SC_SMALL_MAXCLASS);
|
||||||
assert(tcache_salloc(tsd_tsdn(tsd), ptr) <= tcache_maxclass);
|
assert(tcache_salloc(tsd_tsdn(tsd), ptr) <= tcache_maxclass);
|
||||||
|
|
||||||
if (slow_path && config_fill && unlikely(opt_junk_free)) {
|
if (slow_path && config_fill && unlikely(opt_junk_free)) {
|
||||||
@ -215,6 +216,9 @@ JEMALLOC_ALWAYS_INLINE tcache_t *
|
|||||||
tcaches_get(tsd_t *tsd, unsigned ind) {
|
tcaches_get(tsd_t *tsd, unsigned ind) {
|
||||||
tcaches_t *elm = &tcaches[ind];
|
tcaches_t *elm = &tcaches[ind];
|
||||||
if (unlikely(elm->tcache == NULL)) {
|
if (unlikely(elm->tcache == NULL)) {
|
||||||
|
malloc_printf("<jemalloc>: invalid tcache id (%u).\n", ind);
|
||||||
|
abort();
|
||||||
|
} else if (unlikely(elm->tcache == TCACHES_ELM_NEED_REINIT)) {
|
||||||
elm->tcache = tcache_create_explicit(tsd);
|
elm->tcache = tcache_create_explicit(tsd);
|
||||||
}
|
}
|
||||||
return elm->tcache;
|
return elm->tcache;
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
#ifndef JEMALLOC_INTERNAL_TCACHE_STRUCTS_H
|
#ifndef JEMALLOC_INTERNAL_TCACHE_STRUCTS_H
|
||||||
#define JEMALLOC_INTERNAL_TCACHE_STRUCTS_H
|
#define JEMALLOC_INTERNAL_TCACHE_STRUCTS_H
|
||||||
|
|
||||||
#include "jemalloc/internal/ql.h"
|
|
||||||
#include "jemalloc/internal/size_classes.h"
|
|
||||||
#include "jemalloc/internal/cache_bin.h"
|
#include "jemalloc/internal/cache_bin.h"
|
||||||
|
#include "jemalloc/internal/ql.h"
|
||||||
|
#include "jemalloc/internal/sc.h"
|
||||||
#include "jemalloc/internal/ticker.h"
|
#include "jemalloc/internal/ticker.h"
|
||||||
|
#include "jemalloc/internal/tsd_types.h"
|
||||||
|
|
||||||
|
/* Various uses of this struct need it to be a named type. */
|
||||||
|
typedef ql_elm(tsd_t) tsd_link_t;
|
||||||
|
|
||||||
struct tcache_s {
|
struct tcache_s {
|
||||||
/*
|
/*
|
||||||
@ -21,7 +25,7 @@ struct tcache_s {
|
|||||||
* During tcache initialization, the avail pointer in each element of
|
* During tcache initialization, the avail pointer in each element of
|
||||||
* tbins is initialized to point to the proper offset within this array.
|
* tbins is initialized to point to the proper offset within this array.
|
||||||
*/
|
*/
|
||||||
cache_bin_t bins_small[NBINS];
|
cache_bin_t bins_small[SC_NBINS];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This data is less hot; we can be a little less careful with our
|
* This data is less hot; we can be a little less careful with our
|
||||||
@ -29,6 +33,11 @@ struct tcache_s {
|
|||||||
*/
|
*/
|
||||||
/* Lets us track all the tcaches in an arena. */
|
/* Lets us track all the tcaches in an arena. */
|
||||||
ql_elm(tcache_t) link;
|
ql_elm(tcache_t) link;
|
||||||
|
|
||||||
|
/* Logically scoped to tsd, but put here for cache layout reasons. */
|
||||||
|
ql_elm(tsd_t) tsd_link;
|
||||||
|
bool in_hook;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The descriptor lets the arena find our cache bins without seeing the
|
* The descriptor lets the arena find our cache bins without seeing the
|
||||||
* tcache definition. This enables arenas to aggregate stats across
|
* tcache definition. This enables arenas to aggregate stats across
|
||||||
@ -41,13 +50,13 @@ struct tcache_s {
|
|||||||
/* Next bin to GC. */
|
/* Next bin to GC. */
|
||||||
szind_t next_gc_bin;
|
szind_t next_gc_bin;
|
||||||
/* For small bins, fill (ncached_max >> lg_fill_div). */
|
/* For small bins, fill (ncached_max >> lg_fill_div). */
|
||||||
uint8_t lg_fill_div[NBINS];
|
uint8_t lg_fill_div[SC_NBINS];
|
||||||
/*
|
/*
|
||||||
* We put the cache bins for large size classes at the end of the
|
* We put the cache bins for large size classes at the end of the
|
||||||
* struct, since some of them might not get used. This might end up
|
* struct, since some of them might not get used. This might end up
|
||||||
* letting us avoid touching an extra page if we don't have to.
|
* letting us avoid touching an extra page if we don't have to.
|
||||||
*/
|
*/
|
||||||
cache_bin_t bins_large[NSIZES-NBINS];
|
cache_bin_t bins_large[SC_NSIZES-SC_NBINS];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Linkage for list of available (previously used) explicit tcache IDs. */
|
/* Linkage for list of available (previously used) explicit tcache IDs. */
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef JEMALLOC_INTERNAL_TCACHE_TYPES_H
|
#ifndef JEMALLOC_INTERNAL_TCACHE_TYPES_H
|
||||||
#define JEMALLOC_INTERNAL_TCACHE_TYPES_H
|
#define JEMALLOC_INTERNAL_TCACHE_TYPES_H
|
||||||
|
|
||||||
#include "jemalloc/internal/size_classes.h"
|
#include "jemalloc/internal/sc.h"
|
||||||
|
|
||||||
typedef struct tcache_s tcache_t;
|
typedef struct tcache_s tcache_t;
|
||||||
typedef struct tcaches_s tcaches_t;
|
typedef struct tcaches_s tcaches_t;
|
||||||
@ -45,7 +45,7 @@ typedef struct tcaches_s tcaches_t;
|
|||||||
|
|
||||||
/* Number of tcache allocation/deallocation events between incremental GCs. */
|
/* Number of tcache allocation/deallocation events between incremental GCs. */
|
||||||
#define TCACHE_GC_INCR \
|
#define TCACHE_GC_INCR \
|
||||||
((TCACHE_GC_SWEEP / NBINS) + ((TCACHE_GC_SWEEP / NBINS == 0) ? 0 : 1))
|
((TCACHE_GC_SWEEP / SC_NBINS) + ((TCACHE_GC_SWEEP / SC_NBINS == 0) ? 0 : 1))
|
||||||
|
|
||||||
/* Used in TSD static initializer only. Real init in tcache_data_init(). */
|
/* Used in TSD static initializer only. Real init in tcache_data_init(). */
|
||||||
#define TCACHE_ZERO_INITIALIZER {0}
|
#define TCACHE_ZERO_INITIALIZER {0}
|
||||||
@ -53,4 +53,7 @@ typedef struct tcaches_s tcaches_t;
|
|||||||
/* Used in TSD static initializer only. Will be initialized to opt_tcache. */
|
/* Used in TSD static initializer only. Will be initialized to opt_tcache. */
|
||||||
#define TCACHE_ENABLED_ZERO_INITIALIZER false
|
#define TCACHE_ENABLED_ZERO_INITIALIZER false
|
||||||
|
|
||||||
|
/* Used for explicit tcache only. Means flushed but not destroyed. */
|
||||||
|
#define TCACHES_ELM_NEED_REINIT ((tcache_t *)(uintptr_t)1)
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_TCACHE_TYPES_H */
|
#endif /* JEMALLOC_INTERNAL_TCACHE_TYPES_H */
|
||||||
|
19
deps/jemalloc/include/jemalloc/internal/test_hooks.h
vendored
Normal file
19
deps/jemalloc/include/jemalloc/internal/test_hooks.h
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef JEMALLOC_INTERNAL_TEST_HOOKS_H
|
||||||
|
#define JEMALLOC_INTERNAL_TEST_HOOKS_H
|
||||||
|
|
||||||
|
extern JEMALLOC_EXPORT void (*test_hooks_arena_new_hook)();
|
||||||
|
extern JEMALLOC_EXPORT void (*test_hooks_libc_hook)();
|
||||||
|
|
||||||
|
#define JEMALLOC_HOOK(fn, hook) ((void)(hook != NULL && (hook(), 0)), fn)
|
||||||
|
|
||||||
|
#define open JEMALLOC_HOOK(open, test_hooks_libc_hook)
|
||||||
|
#define read JEMALLOC_HOOK(read, test_hooks_libc_hook)
|
||||||
|
#define write JEMALLOC_HOOK(write, test_hooks_libc_hook)
|
||||||
|
#define readlink JEMALLOC_HOOK(readlink, test_hooks_libc_hook)
|
||||||
|
#define close JEMALLOC_HOOK(close, test_hooks_libc_hook)
|
||||||
|
#define creat JEMALLOC_HOOK(creat, test_hooks_libc_hook)
|
||||||
|
#define secure_getenv JEMALLOC_HOOK(secure_getenv, test_hooks_libc_hook)
|
||||||
|
/* Note that this is undef'd and re-define'd in src/prof.c. */
|
||||||
|
#define _Unwind_Backtrace JEMALLOC_HOOK(_Unwind_Backtrace, test_hooks_libc_hook)
|
||||||
|
|
||||||
|
#endif /* JEMALLOC_INTERNAL_TEST_HOOKS_H */
|
13
deps/jemalloc/include/jemalloc/internal/ticker.h
vendored
13
deps/jemalloc/include/jemalloc/internal/ticker.h
vendored
@ -75,4 +75,17 @@ ticker_tick(ticker_t *ticker) {
|
|||||||
return ticker_ticks(ticker, 1);
|
return ticker_ticks(ticker, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to tick. If ticker would fire, return true, but rely on
|
||||||
|
* slowpath to reset ticker.
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
ticker_trytick(ticker_t *ticker) {
|
||||||
|
--ticker->tick;
|
||||||
|
if (unlikely(ticker->tick < 0)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_TICKER_H */
|
#endif /* JEMALLOC_INTERNAL_TICKER_H */
|
||||||
|
153
deps/jemalloc/include/jemalloc/internal/tsd.h
vendored
153
deps/jemalloc/include/jemalloc/internal/tsd.h
vendored
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "jemalloc/internal/arena_types.h"
|
#include "jemalloc/internal/arena_types.h"
|
||||||
#include "jemalloc/internal/assert.h"
|
#include "jemalloc/internal/assert.h"
|
||||||
|
#include "jemalloc/internal/bin_types.h"
|
||||||
#include "jemalloc/internal/jemalloc_internal_externs.h"
|
#include "jemalloc/internal/jemalloc_internal_externs.h"
|
||||||
#include "jemalloc/internal/prof_types.h"
|
#include "jemalloc/internal/prof_types.h"
|
||||||
#include "jemalloc/internal/ql.h"
|
#include "jemalloc/internal/ql.h"
|
||||||
@ -68,17 +69,19 @@ typedef void (*test_callback_t)(int *);
|
|||||||
O(offset_state, uint64_t, uint64_t) \
|
O(offset_state, uint64_t, uint64_t) \
|
||||||
O(thread_allocated, uint64_t, uint64_t) \
|
O(thread_allocated, uint64_t, uint64_t) \
|
||||||
O(thread_deallocated, uint64_t, uint64_t) \
|
O(thread_deallocated, uint64_t, uint64_t) \
|
||||||
|
O(bytes_until_sample, int64_t, int64_t) \
|
||||||
O(prof_tdata, prof_tdata_t *, prof_tdata_t *) \
|
O(prof_tdata, prof_tdata_t *, prof_tdata_t *) \
|
||||||
O(rtree_ctx, rtree_ctx_t, rtree_ctx_t) \
|
O(rtree_ctx, rtree_ctx_t, rtree_ctx_t) \
|
||||||
O(iarena, arena_t *, arena_t *) \
|
O(iarena, arena_t *, arena_t *) \
|
||||||
O(arena, arena_t *, arena_t *) \
|
O(arena, arena_t *, arena_t *) \
|
||||||
O(arenas_tdata, arena_tdata_t *, arena_tdata_t *)\
|
O(arenas_tdata, arena_tdata_t *, arena_tdata_t *)\
|
||||||
|
O(binshards, tsd_binshards_t, tsd_binshards_t)\
|
||||||
O(tcache, tcache_t, tcache_t) \
|
O(tcache, tcache_t, tcache_t) \
|
||||||
O(witness_tsd, witness_tsd_t, witness_tsdn_t) \
|
O(witness_tsd, witness_tsd_t, witness_tsdn_t) \
|
||||||
MALLOC_TEST_TSD
|
MALLOC_TEST_TSD
|
||||||
|
|
||||||
#define TSD_INITIALIZER { \
|
#define TSD_INITIALIZER { \
|
||||||
tsd_state_uninitialized, \
|
ATOMIC_INIT(tsd_state_uninitialized), \
|
||||||
TCACHE_ENABLED_ZERO_INITIALIZER, \
|
TCACHE_ENABLED_ZERO_INITIALIZER, \
|
||||||
false, \
|
false, \
|
||||||
0, \
|
0, \
|
||||||
@ -86,29 +89,97 @@ typedef void (*test_callback_t)(int *);
|
|||||||
0, \
|
0, \
|
||||||
0, \
|
0, \
|
||||||
0, \
|
0, \
|
||||||
|
0, \
|
||||||
NULL, \
|
NULL, \
|
||||||
RTREE_CTX_ZERO_INITIALIZER, \
|
RTREE_CTX_ZERO_INITIALIZER, \
|
||||||
NULL, \
|
NULL, \
|
||||||
NULL, \
|
NULL, \
|
||||||
NULL, \
|
NULL, \
|
||||||
|
TSD_BINSHARDS_ZERO_INITIALIZER, \
|
||||||
TCACHE_ZERO_INITIALIZER, \
|
TCACHE_ZERO_INITIALIZER, \
|
||||||
WITNESS_TSD_INITIALIZER \
|
WITNESS_TSD_INITIALIZER \
|
||||||
MALLOC_TEST_TSD_INITIALIZER \
|
MALLOC_TEST_TSD_INITIALIZER \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *malloc_tsd_malloc(size_t size);
|
||||||
|
void malloc_tsd_dalloc(void *wrapper);
|
||||||
|
void malloc_tsd_cleanup_register(bool (*f)(void));
|
||||||
|
tsd_t *malloc_tsd_boot0(void);
|
||||||
|
void malloc_tsd_boot1(void);
|
||||||
|
void tsd_cleanup(void *arg);
|
||||||
|
tsd_t *tsd_fetch_slow(tsd_t *tsd, bool internal);
|
||||||
|
void tsd_state_set(tsd_t *tsd, uint8_t new_state);
|
||||||
|
void tsd_slow_update(tsd_t *tsd);
|
||||||
|
void tsd_prefork(tsd_t *tsd);
|
||||||
|
void tsd_postfork_parent(tsd_t *tsd);
|
||||||
|
void tsd_postfork_child(tsd_t *tsd);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call ..._inc when your module wants to take all threads down the slow paths,
|
||||||
|
* and ..._dec when it no longer needs to.
|
||||||
|
*/
|
||||||
|
void tsd_global_slow_inc(tsdn_t *tsdn);
|
||||||
|
void tsd_global_slow_dec(tsdn_t *tsdn);
|
||||||
|
bool tsd_global_slow();
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
tsd_state_nominal = 0, /* Common case --> jnz. */
|
/* Common case --> jnz. */
|
||||||
tsd_state_nominal_slow = 1, /* Initialized but on slow path. */
|
tsd_state_nominal = 0,
|
||||||
/* the above 2 nominal states should be lower values. */
|
/* Initialized but on slow path. */
|
||||||
tsd_state_nominal_max = 1, /* used for comparison only. */
|
tsd_state_nominal_slow = 1,
|
||||||
tsd_state_minimal_initialized = 2,
|
/*
|
||||||
tsd_state_purgatory = 3,
|
* Some thread has changed global state in such a way that all nominal
|
||||||
tsd_state_reincarnated = 4,
|
* threads need to recompute their fast / slow status the next time they
|
||||||
tsd_state_uninitialized = 5
|
* get a chance.
|
||||||
|
*
|
||||||
|
* Any thread can change another thread's status *to* recompute, but
|
||||||
|
* threads are the only ones who can change their status *from*
|
||||||
|
* recompute.
|
||||||
|
*/
|
||||||
|
tsd_state_nominal_recompute = 2,
|
||||||
|
/*
|
||||||
|
* The above nominal states should be lower values. We use
|
||||||
|
* tsd_nominal_max to separate nominal states from threads in the
|
||||||
|
* process of being born / dying.
|
||||||
|
*/
|
||||||
|
tsd_state_nominal_max = 2,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A thread might free() during its death as its only allocator action;
|
||||||
|
* in such scenarios, we need tsd, but set up in such a way that no
|
||||||
|
* cleanup is necessary.
|
||||||
|
*/
|
||||||
|
tsd_state_minimal_initialized = 3,
|
||||||
|
/* States during which we know we're in thread death. */
|
||||||
|
tsd_state_purgatory = 4,
|
||||||
|
tsd_state_reincarnated = 5,
|
||||||
|
/*
|
||||||
|
* What it says on the tin; tsd that hasn't been initialized. Note
|
||||||
|
* that even when the tsd struct lives in TLS, when need to keep track
|
||||||
|
* of stuff like whether or not our pthread destructors have been
|
||||||
|
* scheduled, so this really truly is different than the nominal state.
|
||||||
|
*/
|
||||||
|
tsd_state_uninitialized = 6
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Manually limit tsd_state_t to a single byte. */
|
/*
|
||||||
typedef uint8_t tsd_state_t;
|
* Some TSD accesses can only be done in a nominal state. To enforce this, we
|
||||||
|
* wrap TSD member access in a function that asserts on TSD state, and mangle
|
||||||
|
* field names to prevent touching them accidentally.
|
||||||
|
*/
|
||||||
|
#define TSD_MANGLE(n) cant_access_tsd_items_directly_use_a_getter_or_setter_##n
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_U8_ATOMICS
|
||||||
|
# define tsd_state_t atomic_u8_t
|
||||||
|
# define tsd_atomic_load atomic_load_u8
|
||||||
|
# define tsd_atomic_store atomic_store_u8
|
||||||
|
# define tsd_atomic_exchange atomic_exchange_u8
|
||||||
|
#else
|
||||||
|
# define tsd_state_t atomic_u32_t
|
||||||
|
# define tsd_atomic_load atomic_load_u32
|
||||||
|
# define tsd_atomic_store atomic_store_u32
|
||||||
|
# define tsd_atomic_exchange atomic_exchange_u32
|
||||||
|
#endif
|
||||||
|
|
||||||
/* The actual tsd. */
|
/* The actual tsd. */
|
||||||
struct tsd_s {
|
struct tsd_s {
|
||||||
@ -117,13 +188,29 @@ struct tsd_s {
|
|||||||
* module. Access any thread-local state through the getters and
|
* module. Access any thread-local state through the getters and
|
||||||
* setters below.
|
* setters below.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We manually limit the state to just a single byte. Unless the 8-bit
|
||||||
|
* atomics are unavailable (which is rare).
|
||||||
|
*/
|
||||||
tsd_state_t state;
|
tsd_state_t state;
|
||||||
#define O(n, t, nt) \
|
#define O(n, t, nt) \
|
||||||
t use_a_getter_or_setter_instead_##n;
|
t TSD_MANGLE(n);
|
||||||
MALLOC_TSD
|
MALLOC_TSD
|
||||||
#undef O
|
#undef O
|
||||||
};
|
};
|
||||||
|
|
||||||
|
JEMALLOC_ALWAYS_INLINE uint8_t
|
||||||
|
tsd_state_get(tsd_t *tsd) {
|
||||||
|
/*
|
||||||
|
* This should be atomic. Unfortunately, compilers right now can't tell
|
||||||
|
* that this can be done as a memory comparison, and forces a load into
|
||||||
|
* a register that hurts fast-path performance.
|
||||||
|
*/
|
||||||
|
/* return atomic_load_u8(&tsd->state, ATOMIC_RELAXED); */
|
||||||
|
return *(uint8_t *)&tsd->state;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wrapper around tsd_t that makes it possible to avoid implicit conversion
|
* Wrapper around tsd_t that makes it possible to avoid implicit conversion
|
||||||
* between tsd_t and tsdn_t, where tsdn_t is "nullable" and has to be
|
* between tsd_t and tsdn_t, where tsdn_t is "nullable" and has to be
|
||||||
@ -150,15 +237,6 @@ tsdn_tsd(tsdn_t *tsdn) {
|
|||||||
return &tsdn->tsd;
|
return &tsdn->tsd;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *malloc_tsd_malloc(size_t size);
|
|
||||||
void malloc_tsd_dalloc(void *wrapper);
|
|
||||||
void malloc_tsd_cleanup_register(bool (*f)(void));
|
|
||||||
tsd_t *malloc_tsd_boot0(void);
|
|
||||||
void malloc_tsd_boot1(void);
|
|
||||||
void tsd_cleanup(void *arg);
|
|
||||||
tsd_t *tsd_fetch_slow(tsd_t *tsd, bool internal);
|
|
||||||
void tsd_slow_update(tsd_t *tsd);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We put the platform-specific data declarations and inlines into their own
|
* We put the platform-specific data declarations and inlines into their own
|
||||||
* header files to avoid cluttering this file. They define tsd_boot0,
|
* header files to avoid cluttering this file. They define tsd_boot0,
|
||||||
@ -182,7 +260,7 @@ void tsd_slow_update(tsd_t *tsd);
|
|||||||
#define O(n, t, nt) \
|
#define O(n, t, nt) \
|
||||||
JEMALLOC_ALWAYS_INLINE t * \
|
JEMALLOC_ALWAYS_INLINE t * \
|
||||||
tsd_##n##p_get_unsafe(tsd_t *tsd) { \
|
tsd_##n##p_get_unsafe(tsd_t *tsd) { \
|
||||||
return &tsd->use_a_getter_or_setter_instead_##n; \
|
return &tsd->TSD_MANGLE(n); \
|
||||||
}
|
}
|
||||||
MALLOC_TSD
|
MALLOC_TSD
|
||||||
#undef O
|
#undef O
|
||||||
@ -191,10 +269,16 @@ MALLOC_TSD
|
|||||||
#define O(n, t, nt) \
|
#define O(n, t, nt) \
|
||||||
JEMALLOC_ALWAYS_INLINE t * \
|
JEMALLOC_ALWAYS_INLINE t * \
|
||||||
tsd_##n##p_get(tsd_t *tsd) { \
|
tsd_##n##p_get(tsd_t *tsd) { \
|
||||||
assert(tsd->state == tsd_state_nominal || \
|
/* \
|
||||||
tsd->state == tsd_state_nominal_slow || \
|
* Because the state might change asynchronously if it's \
|
||||||
tsd->state == tsd_state_reincarnated || \
|
* nominal, we need to make sure that we only read it once. \
|
||||||
tsd->state == tsd_state_minimal_initialized); \
|
*/ \
|
||||||
|
uint8_t state = tsd_state_get(tsd); \
|
||||||
|
assert(state == tsd_state_nominal || \
|
||||||
|
state == tsd_state_nominal_slow || \
|
||||||
|
state == tsd_state_nominal_recompute || \
|
||||||
|
state == tsd_state_reincarnated || \
|
||||||
|
state == tsd_state_minimal_initialized); \
|
||||||
return tsd_##n##p_get_unsafe(tsd); \
|
return tsd_##n##p_get_unsafe(tsd); \
|
||||||
}
|
}
|
||||||
MALLOC_TSD
|
MALLOC_TSD
|
||||||
@ -229,8 +313,8 @@ MALLOC_TSD
|
|||||||
#define O(n, t, nt) \
|
#define O(n, t, nt) \
|
||||||
JEMALLOC_ALWAYS_INLINE void \
|
JEMALLOC_ALWAYS_INLINE void \
|
||||||
tsd_##n##_set(tsd_t *tsd, t val) { \
|
tsd_##n##_set(tsd_t *tsd, t val) { \
|
||||||
assert(tsd->state != tsd_state_reincarnated && \
|
assert(tsd_state_get(tsd) != tsd_state_reincarnated && \
|
||||||
tsd->state != tsd_state_minimal_initialized); \
|
tsd_state_get(tsd) != tsd_state_minimal_initialized); \
|
||||||
*tsd_##n##p_get(tsd) = val; \
|
*tsd_##n##p_get(tsd) = val; \
|
||||||
}
|
}
|
||||||
MALLOC_TSD
|
MALLOC_TSD
|
||||||
@ -238,13 +322,18 @@ MALLOC_TSD
|
|||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
tsd_assert_fast(tsd_t *tsd) {
|
tsd_assert_fast(tsd_t *tsd) {
|
||||||
|
/*
|
||||||
|
* Note that our fastness assertion does *not* include global slowness
|
||||||
|
* counters; it's not in general possible to ensure that they won't
|
||||||
|
* change asynchronously from underneath us.
|
||||||
|
*/
|
||||||
assert(!malloc_slow && tsd_tcache_enabled_get(tsd) &&
|
assert(!malloc_slow && tsd_tcache_enabled_get(tsd) &&
|
||||||
tsd_reentrancy_level_get(tsd) == 0);
|
tsd_reentrancy_level_get(tsd) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE bool
|
JEMALLOC_ALWAYS_INLINE bool
|
||||||
tsd_fast(tsd_t *tsd) {
|
tsd_fast(tsd_t *tsd) {
|
||||||
bool fast = (tsd->state == tsd_state_nominal);
|
bool fast = (tsd_state_get(tsd) == tsd_state_nominal);
|
||||||
if (fast) {
|
if (fast) {
|
||||||
tsd_assert_fast(tsd);
|
tsd_assert_fast(tsd);
|
||||||
}
|
}
|
||||||
@ -261,7 +350,7 @@ tsd_fetch_impl(bool init, bool minimal) {
|
|||||||
}
|
}
|
||||||
assert(tsd != NULL);
|
assert(tsd != NULL);
|
||||||
|
|
||||||
if (unlikely(tsd->state != tsd_state_nominal)) {
|
if (unlikely(tsd_state_get(tsd) != tsd_state_nominal)) {
|
||||||
return tsd_fetch_slow(tsd, minimal);
|
return tsd_fetch_slow(tsd, minimal);
|
||||||
}
|
}
|
||||||
assert(tsd_fast(tsd));
|
assert(tsd_fast(tsd));
|
||||||
@ -281,7 +370,7 @@ JEMALLOC_ALWAYS_INLINE tsd_t *
|
|||||||
tsd_internal_fetch(void) {
|
tsd_internal_fetch(void) {
|
||||||
tsd_t *tsd = tsd_fetch_min();
|
tsd_t *tsd = tsd_fetch_min();
|
||||||
/* Use reincarnated state to prevent full initialization. */
|
/* Use reincarnated state to prevent full initialization. */
|
||||||
tsd->state = tsd_state_reincarnated;
|
tsd_state_set(tsd, tsd_state_reincarnated);
|
||||||
|
|
||||||
return tsd;
|
return tsd;
|
||||||
}
|
}
|
||||||
@ -293,7 +382,7 @@ tsd_fetch(void) {
|
|||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
tsd_nominal(tsd_t *tsd) {
|
tsd_nominal(tsd_t *tsd) {
|
||||||
return (tsd->state <= tsd_state_nominal_max);
|
return (tsd_state_get(tsd) <= tsd_state_nominal_max);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE tsdn_t *
|
JEMALLOC_ALWAYS_INLINE tsdn_t *
|
||||||
|
@ -77,7 +77,10 @@ tsd_wrapper_get(bool init) {
|
|||||||
abort();
|
abort();
|
||||||
} else {
|
} else {
|
||||||
wrapper->initialized = false;
|
wrapper->initialized = false;
|
||||||
|
JEMALLOC_DIAGNOSTIC_PUSH
|
||||||
|
JEMALLOC_DIAGNOSTIC_IGNORE_MISSING_STRUCT_FIELD_INITIALIZERS
|
||||||
tsd_t initializer = TSD_INITIALIZER;
|
tsd_t initializer = TSD_INITIALIZER;
|
||||||
|
JEMALLOC_DIAGNOSTIC_POP
|
||||||
wrapper->val = initializer;
|
wrapper->val = initializer;
|
||||||
}
|
}
|
||||||
tsd_wrapper_set(wrapper);
|
tsd_wrapper_set(wrapper);
|
||||||
@ -107,7 +110,10 @@ tsd_boot1(void) {
|
|||||||
tsd_boot_wrapper.initialized = false;
|
tsd_boot_wrapper.initialized = false;
|
||||||
tsd_cleanup(&tsd_boot_wrapper.val);
|
tsd_cleanup(&tsd_boot_wrapper.val);
|
||||||
wrapper->initialized = false;
|
wrapper->initialized = false;
|
||||||
|
JEMALLOC_DIAGNOSTIC_PUSH
|
||||||
|
JEMALLOC_DIAGNOSTIC_IGNORE_MISSING_STRUCT_FIELD_INITIALIZERS
|
||||||
tsd_t initializer = TSD_INITIALIZER;
|
tsd_t initializer = TSD_INITIALIZER;
|
||||||
|
JEMALLOC_DIAGNOSTIC_POP
|
||||||
wrapper->val = initializer;
|
wrapper->val = initializer;
|
||||||
tsd_wrapper_set(wrapper);
|
tsd_wrapper_set(wrapper);
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,10 @@
|
|||||||
#endif
|
#endif
|
||||||
#define JEMALLOC_INTERNAL_TSD_MALLOC_THREAD_CLEANUP_H
|
#define JEMALLOC_INTERNAL_TSD_MALLOC_THREAD_CLEANUP_H
|
||||||
|
|
||||||
extern __thread tsd_t tsd_tls;
|
#define JEMALLOC_TSD_TYPE_ATTR(type) __thread type JEMALLOC_TLS_MODEL
|
||||||
extern __thread bool tsd_initialized;
|
|
||||||
|
extern JEMALLOC_TSD_TYPE_ATTR(tsd_t) tsd_tls;
|
||||||
|
extern JEMALLOC_TSD_TYPE_ATTR(bool) tsd_initialized;
|
||||||
extern bool tsd_booted;
|
extern bool tsd_booted;
|
||||||
|
|
||||||
/* Initialization/cleanup. */
|
/* Initialization/cleanup. */
|
||||||
@ -47,7 +49,6 @@ tsd_get_allocates(void) {
|
|||||||
/* Get/set. */
|
/* Get/set. */
|
||||||
JEMALLOC_ALWAYS_INLINE tsd_t *
|
JEMALLOC_ALWAYS_INLINE tsd_t *
|
||||||
tsd_get(bool init) {
|
tsd_get(bool init) {
|
||||||
assert(tsd_booted);
|
|
||||||
return &tsd_tls;
|
return &tsd_tls;
|
||||||
}
|
}
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
#endif
|
#endif
|
||||||
#define JEMALLOC_INTERNAL_TSD_TLS_H
|
#define JEMALLOC_INTERNAL_TSD_TLS_H
|
||||||
|
|
||||||
extern __thread tsd_t tsd_tls;
|
#define JEMALLOC_TSD_TYPE_ATTR(type) __thread type JEMALLOC_TLS_MODEL
|
||||||
|
|
||||||
|
extern JEMALLOC_TSD_TYPE_ATTR(tsd_t) tsd_tls;
|
||||||
extern pthread_key_t tsd_tsd;
|
extern pthread_key_t tsd_tsd;
|
||||||
extern bool tsd_booted;
|
extern bool tsd_booted;
|
||||||
|
|
||||||
@ -39,8 +41,7 @@ tsd_get_allocates(void) {
|
|||||||
|
|
||||||
/* Get/set. */
|
/* Get/set. */
|
||||||
JEMALLOC_ALWAYS_INLINE tsd_t *
|
JEMALLOC_ALWAYS_INLINE tsd_t *
|
||||||
tsd_get(UNUSED bool init) {
|
tsd_get(bool init) {
|
||||||
assert(tsd_booted);
|
|
||||||
return &tsd_tls;
|
return &tsd_tls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,9 +27,9 @@
|
|||||||
#define WITNESS_RANK_PROF_BT2GCTX 6U
|
#define WITNESS_RANK_PROF_BT2GCTX 6U
|
||||||
#define WITNESS_RANK_PROF_TDATAS 7U
|
#define WITNESS_RANK_PROF_TDATAS 7U
|
||||||
#define WITNESS_RANK_PROF_TDATA 8U
|
#define WITNESS_RANK_PROF_TDATA 8U
|
||||||
#define WITNESS_RANK_PROF_GCTX 9U
|
#define WITNESS_RANK_PROF_LOG 9U
|
||||||
|
#define WITNESS_RANK_PROF_GCTX 10U
|
||||||
#define WITNESS_RANK_BACKGROUND_THREAD 10U
|
#define WITNESS_RANK_BACKGROUND_THREAD 11U
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used as an argument to witness_assert_depth_to_rank() in order to validate
|
* Used as an argument to witness_assert_depth_to_rank() in order to validate
|
||||||
@ -37,18 +37,19 @@
|
|||||||
* witness_assert_depth_to_rank() is inclusive rather than exclusive, this
|
* witness_assert_depth_to_rank() is inclusive rather than exclusive, this
|
||||||
* definition can have the same value as the minimally ranked core lock.
|
* definition can have the same value as the minimally ranked core lock.
|
||||||
*/
|
*/
|
||||||
#define WITNESS_RANK_CORE 11U
|
#define WITNESS_RANK_CORE 12U
|
||||||
|
|
||||||
#define WITNESS_RANK_DECAY 11U
|
#define WITNESS_RANK_DECAY 12U
|
||||||
#define WITNESS_RANK_TCACHE_QL 12U
|
#define WITNESS_RANK_TCACHE_QL 13U
|
||||||
#define WITNESS_RANK_EXTENT_GROW 13U
|
#define WITNESS_RANK_EXTENT_GROW 14U
|
||||||
#define WITNESS_RANK_EXTENTS 14U
|
#define WITNESS_RANK_EXTENTS 15U
|
||||||
#define WITNESS_RANK_EXTENT_AVAIL 15U
|
#define WITNESS_RANK_EXTENT_AVAIL 16U
|
||||||
|
|
||||||
#define WITNESS_RANK_EXTENT_POOL 16U
|
#define WITNESS_RANK_EXTENT_POOL 17U
|
||||||
#define WITNESS_RANK_RTREE 17U
|
#define WITNESS_RANK_RTREE 18U
|
||||||
#define WITNESS_RANK_BASE 18U
|
#define WITNESS_RANK_BASE 19U
|
||||||
#define WITNESS_RANK_ARENA_LARGE 19U
|
#define WITNESS_RANK_ARENA_LARGE 20U
|
||||||
|
#define WITNESS_RANK_HOOK 21U
|
||||||
|
|
||||||
#define WITNESS_RANK_LEAF 0xffffffffU
|
#define WITNESS_RANK_LEAF 0xffffffffU
|
||||||
#define WITNESS_RANK_BIN WITNESS_RANK_LEAF
|
#define WITNESS_RANK_BIN WITNESS_RANK_LEAF
|
||||||
|
@ -4,6 +4,9 @@
|
|||||||
/* Defined if alloc_size attribute is supported. */
|
/* Defined if alloc_size attribute is supported. */
|
||||||
#undef JEMALLOC_HAVE_ATTR_ALLOC_SIZE
|
#undef JEMALLOC_HAVE_ATTR_ALLOC_SIZE
|
||||||
|
|
||||||
|
/* Defined if format_arg(...) attribute is supported. */
|
||||||
|
#undef JEMALLOC_HAVE_ATTR_FORMAT_ARG
|
||||||
|
|
||||||
/* Defined if format(gnu_printf, ...) attribute is supported. */
|
/* Defined if format(gnu_printf, ...) attribute is supported. */
|
||||||
#undef JEMALLOC_HAVE_ATTR_FORMAT_GNU_PRINTF
|
#undef JEMALLOC_HAVE_ATTR_FORMAT_GNU_PRINTF
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#define JEMALLOC_VERSION_BUGFIX @jemalloc_version_bugfix@
|
#define JEMALLOC_VERSION_BUGFIX @jemalloc_version_bugfix@
|
||||||
#define JEMALLOC_VERSION_NREV @jemalloc_version_nrev@
|
#define JEMALLOC_VERSION_NREV @jemalloc_version_nrev@
|
||||||
#define JEMALLOC_VERSION_GID "@jemalloc_version_gid@"
|
#define JEMALLOC_VERSION_GID "@jemalloc_version_gid@"
|
||||||
|
#define JEMALLOC_VERSION_GID_IDENT @jemalloc_version_gid@
|
||||||
|
|
||||||
#define MALLOCX_LG_ALIGN(la) ((int)(la))
|
#define MALLOCX_LG_ALIGN(la) ((int)(la))
|
||||||
#if LG_SIZEOF_PTR == 2
|
#if LG_SIZEOF_PTR == 2
|
||||||
@ -68,6 +69,7 @@
|
|||||||
# define JEMALLOC_EXPORT __declspec(dllimport)
|
# define JEMALLOC_EXPORT __declspec(dllimport)
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
|
# define JEMALLOC_FORMAT_ARG(i)
|
||||||
# define JEMALLOC_FORMAT_PRINTF(s, i)
|
# define JEMALLOC_FORMAT_PRINTF(s, i)
|
||||||
# define JEMALLOC_NOINLINE __declspec(noinline)
|
# define JEMALLOC_NOINLINE __declspec(noinline)
|
||||||
# ifdef __cplusplus
|
# ifdef __cplusplus
|
||||||
@ -95,6 +97,11 @@
|
|||||||
# ifndef JEMALLOC_EXPORT
|
# ifndef JEMALLOC_EXPORT
|
||||||
# define JEMALLOC_EXPORT JEMALLOC_ATTR(visibility("default"))
|
# define JEMALLOC_EXPORT JEMALLOC_ATTR(visibility("default"))
|
||||||
# endif
|
# endif
|
||||||
|
# ifdef JEMALLOC_HAVE_ATTR_FORMAT_ARG
|
||||||
|
# define JEMALLOC_FORMAT_ARG(i) JEMALLOC_ATTR(__format_arg__(3))
|
||||||
|
# else
|
||||||
|
# define JEMALLOC_FORMAT_ARG(i)
|
||||||
|
# endif
|
||||||
# ifdef JEMALLOC_HAVE_ATTR_FORMAT_GNU_PRINTF
|
# ifdef JEMALLOC_HAVE_ATTR_FORMAT_GNU_PRINTF
|
||||||
# define JEMALLOC_FORMAT_PRINTF(s, i) JEMALLOC_ATTR(format(gnu_printf, s, i))
|
# define JEMALLOC_FORMAT_PRINTF(s, i) JEMALLOC_ATTR(format(gnu_printf, s, i))
|
||||||
# elif defined(JEMALLOC_HAVE_ATTR_FORMAT_PRINTF)
|
# elif defined(JEMALLOC_HAVE_ATTR_FORMAT_PRINTF)
|
||||||
|
@ -47,7 +47,7 @@
|
|||||||
<ClCompile Include="..\..\..\..\src\extent_dss.c" />
|
<ClCompile Include="..\..\..\..\src\extent_dss.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\extent_mmap.c" />
|
<ClCompile Include="..\..\..\..\src\extent_mmap.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\hash.c" />
|
<ClCompile Include="..\..\..\..\src\hash.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\hooks.c" />
|
<ClCompile Include="..\..\..\..\src\hook.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\jemalloc.c" />
|
<ClCompile Include="..\..\..\..\src\jemalloc.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\large.c" />
|
<ClCompile Include="..\..\..\..\src\large.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\log.c" />
|
<ClCompile Include="..\..\..\..\src\log.c" />
|
||||||
@ -59,12 +59,14 @@
|
|||||||
<ClCompile Include="..\..\..\..\src\prng.c" />
|
<ClCompile Include="..\..\..\..\src\prng.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\prof.c" />
|
<ClCompile Include="..\..\..\..\src\prof.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\rtree.c" />
|
<ClCompile Include="..\..\..\..\src\rtree.c" />
|
||||||
|
<ClCompile Include="..\..\..\..\src\sc.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\stats.c" />
|
<ClCompile Include="..\..\..\..\src\stats.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\sz.c" />
|
<ClCompile Include="..\..\..\..\src\sz.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\tcache.c" />
|
<ClCompile Include="..\..\..\..\src\tcache.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\ticker.c" />
|
<ClCompile Include="..\..\..\..\src\ticker.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\tsd.c" />
|
<ClCompile Include="..\..\..\..\src\tsd.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\witness.c" />
|
<ClCompile Include="..\..\..\..\src\witness.c" />
|
||||||
|
<ClCompile Include="..\..\..\..\src\safety_check.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
<ProjectGuid>{8D6BB292-9E1C-413D-9F98-4864BDC1514A}</ProjectGuid>
|
<ProjectGuid>{8D6BB292-9E1C-413D-9F98-4864BDC1514A}</ProjectGuid>
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
<ClCompile Include="..\..\..\..\src\hash.c">
|
<ClCompile Include="..\..\..\..\src\hash.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\..\src\hooks.c">
|
<ClCompile Include="..\..\..\..\src\hook.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\..\src\jemalloc.c">
|
<ClCompile Include="..\..\..\..\src\jemalloc.c">
|
||||||
@ -70,6 +70,9 @@
|
|||||||
<ClCompile Include="..\..\..\..\src\rtree.c">
|
<ClCompile Include="..\..\..\..\src\rtree.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\..\src\sc.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\..\src\stats.c">
|
<ClCompile Include="..\..\..\..\src\stats.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -97,5 +100,8 @@
|
|||||||
<ClCompile Include="..\..\..\..\src\div.c">
|
<ClCompile Include="..\..\..\..\src\div.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\..\src\safety_check.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -47,7 +47,7 @@
|
|||||||
<ClCompile Include="..\..\..\..\src\extent_dss.c" />
|
<ClCompile Include="..\..\..\..\src\extent_dss.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\extent_mmap.c" />
|
<ClCompile Include="..\..\..\..\src\extent_mmap.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\hash.c" />
|
<ClCompile Include="..\..\..\..\src\hash.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\hooks.c" />
|
<ClCompile Include="..\..\..\..\src\hook.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\jemalloc.c" />
|
<ClCompile Include="..\..\..\..\src\jemalloc.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\large.c" />
|
<ClCompile Include="..\..\..\..\src\large.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\log.c" />
|
<ClCompile Include="..\..\..\..\src\log.c" />
|
||||||
@ -59,12 +59,15 @@
|
|||||||
<ClCompile Include="..\..\..\..\src\prng.c" />
|
<ClCompile Include="..\..\..\..\src\prng.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\prof.c" />
|
<ClCompile Include="..\..\..\..\src\prof.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\rtree.c" />
|
<ClCompile Include="..\..\..\..\src\rtree.c" />
|
||||||
|
<ClCompile Include="..\..\..\..\src\sc.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\stats.c" />
|
<ClCompile Include="..\..\..\..\src\stats.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\sz.c" />
|
<ClCompile Include="..\..\..\..\src\sz.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\tcache.c" />
|
<ClCompile Include="..\..\..\..\src\tcache.c" />
|
||||||
|
<ClCompile Include="..\..\..\..\src\test_hooks.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\ticker.c" />
|
<ClCompile Include="..\..\..\..\src\ticker.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\tsd.c" />
|
<ClCompile Include="..\..\..\..\src\tsd.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\witness.c" />
|
<ClCompile Include="..\..\..\..\src\witness.c" />
|
||||||
|
<ClCompile Include="..\..\..\..\src\safety_check.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
<ProjectGuid>{8D6BB292-9E1C-413D-9F98-4864BDC1514A}</ProjectGuid>
|
<ProjectGuid>{8D6BB292-9E1C-413D-9F98-4864BDC1514A}</ProjectGuid>
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
<ClCompile Include="..\..\..\..\src\hash.c">
|
<ClCompile Include="..\..\..\..\src\hash.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\..\src\hooks.c">
|
<ClCompile Include="..\..\..\..\src\hook.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\..\src\jemalloc.c">
|
<ClCompile Include="..\..\..\..\src\jemalloc.c">
|
||||||
@ -70,6 +70,9 @@
|
|||||||
<ClCompile Include="..\..\..\..\src\rtree.c">
|
<ClCompile Include="..\..\..\..\src\rtree.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\..\src\sc.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\..\src\stats.c">
|
<ClCompile Include="..\..\..\..\src\stats.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -97,5 +100,11 @@
|
|||||||
<ClCompile Include="..\..\..\..\src\div.c">
|
<ClCompile Include="..\..\..\..\src\div.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\..\src\test_hooks.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\..\src\safety_check.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
26
deps/jemalloc/scripts/gen_run_tests.py
vendored
26
deps/jemalloc/scripts/gen_run_tests.py
vendored
@ -4,6 +4,7 @@ import sys
|
|||||||
from itertools import combinations
|
from itertools import combinations
|
||||||
from os import uname
|
from os import uname
|
||||||
from multiprocessing import cpu_count
|
from multiprocessing import cpu_count
|
||||||
|
from subprocess import call
|
||||||
|
|
||||||
# Later, we want to test extended vaddr support. Apparently, the "real" way of
|
# Later, we want to test extended vaddr support. Apparently, the "real" way of
|
||||||
# checking this is flaky on OS X.
|
# checking this is flaky on OS X.
|
||||||
@ -13,13 +14,25 @@ nparallel = cpu_count() * 2
|
|||||||
|
|
||||||
uname = uname()[0]
|
uname = uname()[0]
|
||||||
|
|
||||||
|
if "BSD" in uname:
|
||||||
|
make_cmd = 'gmake'
|
||||||
|
else:
|
||||||
|
make_cmd = 'make'
|
||||||
|
|
||||||
def powerset(items):
|
def powerset(items):
|
||||||
result = []
|
result = []
|
||||||
for i in xrange(len(items) + 1):
|
for i in xrange(len(items) + 1):
|
||||||
result += combinations(items, i)
|
result += combinations(items, i)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
possible_compilers = [('gcc', 'g++'), ('clang', 'clang++')]
|
possible_compilers = []
|
||||||
|
for cc, cxx in (['gcc', 'g++'], ['clang', 'clang++']):
|
||||||
|
try:
|
||||||
|
cmd_ret = call([cc, "-v"])
|
||||||
|
if cmd_ret == 0:
|
||||||
|
possible_compilers.append((cc, cxx))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
possible_compiler_opts = [
|
possible_compiler_opts = [
|
||||||
'-m32',
|
'-m32',
|
||||||
]
|
]
|
||||||
@ -27,6 +40,7 @@ possible_config_opts = [
|
|||||||
'--enable-debug',
|
'--enable-debug',
|
||||||
'--enable-prof',
|
'--enable-prof',
|
||||||
'--disable-stats',
|
'--disable-stats',
|
||||||
|
'--enable-opt-safety-checks',
|
||||||
]
|
]
|
||||||
if bits_64:
|
if bits_64:
|
||||||
possible_config_opts.append('--with-lg-vaddr=56')
|
possible_config_opts.append('--with-lg-vaddr=56')
|
||||||
@ -39,7 +53,7 @@ possible_malloc_conf_opts = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
print 'set -e'
|
print 'set -e'
|
||||||
print 'if [ -f Makefile ] ; then make relclean ; fi'
|
print 'if [ -f Makefile ] ; then %(make_cmd)s relclean ; fi' % {'make_cmd': make_cmd}
|
||||||
print 'autoconf'
|
print 'autoconf'
|
||||||
print 'rm -rf run_tests.out'
|
print 'rm -rf run_tests.out'
|
||||||
print 'mkdir run_tests.out'
|
print 'mkdir run_tests.out'
|
||||||
@ -102,11 +116,11 @@ cd run_test_%(ind)d.out
|
|||||||
echo "==> %(config_line)s" >> run_test.log
|
echo "==> %(config_line)s" >> run_test.log
|
||||||
%(config_line)s >> run_test.log 2>&1 || abort
|
%(config_line)s >> run_test.log 2>&1 || abort
|
||||||
|
|
||||||
run_cmd make all tests
|
run_cmd %(make_cmd)s all tests
|
||||||
run_cmd make check
|
run_cmd %(make_cmd)s check
|
||||||
run_cmd make distclean
|
run_cmd %(make_cmd)s distclean
|
||||||
EOF
|
EOF
|
||||||
chmod 755 run_test_%(ind)d.sh""" % {'ind': ind, 'config_line': config_line}
|
chmod 755 run_test_%(ind)d.sh""" % {'ind': ind, 'config_line': config_line, 'make_cmd': make_cmd}
|
||||||
ind += 1
|
ind += 1
|
||||||
|
|
||||||
print 'for i in `seq 0 %(last_ind)d` ; do echo run_test_${i}.sh ; done | xargs -P %(nparallel)d -n 1 sh' % {'last_ind': ind-1, 'nparallel': nparallel}
|
print 'for i in `seq 0 %(last_ind)d` ; do echo run_test_${i}.sh ; done | xargs -P %(nparallel)d -n 1 sh' % {'last_ind': ind-1, 'nparallel': nparallel}
|
||||||
|
90
deps/jemalloc/scripts/gen_travis.py
vendored
90
deps/jemalloc/scripts/gen_travis.py
vendored
@ -4,6 +4,7 @@ from itertools import combinations
|
|||||||
|
|
||||||
travis_template = """\
|
travis_template = """\
|
||||||
language: generic
|
language: generic
|
||||||
|
dist: precise
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
@ -11,6 +12,7 @@ matrix:
|
|||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- autoconf
|
- autoconf
|
||||||
|
- scripts/gen_travis.py > travis_script && diff .travis.yml travis_script
|
||||||
- ./configure ${COMPILER_FLAGS:+ \
|
- ./configure ${COMPILER_FLAGS:+ \
|
||||||
CC="$CC $COMPILER_FLAGS" \
|
CC="$CC $COMPILER_FLAGS" \
|
||||||
CXX="$CXX $COMPILER_FLAGS" } \
|
CXX="$CXX $COMPILER_FLAGS" } \
|
||||||
@ -43,6 +45,8 @@ configure_flag_unusuals = [
|
|||||||
'--enable-debug',
|
'--enable-debug',
|
||||||
'--enable-prof',
|
'--enable-prof',
|
||||||
'--disable-stats',
|
'--disable-stats',
|
||||||
|
'--disable-libdl',
|
||||||
|
'--enable-opt-safety-checks',
|
||||||
]
|
]
|
||||||
|
|
||||||
malloc_conf_unusuals = [
|
malloc_conf_unusuals = [
|
||||||
@ -61,47 +65,85 @@ unusual_combinations_to_test = []
|
|||||||
for i in xrange(MAX_UNUSUAL_OPTIONS + 1):
|
for i in xrange(MAX_UNUSUAL_OPTIONS + 1):
|
||||||
unusual_combinations_to_test += combinations(all_unusuals, i)
|
unusual_combinations_to_test += combinations(all_unusuals, i)
|
||||||
|
|
||||||
include_rows = ""
|
gcc_multilib_set = False
|
||||||
for unusual_combination in unusual_combinations_to_test:
|
# Formats a job from a combination of flags
|
||||||
os = os_default
|
def format_job(combination):
|
||||||
if os_unusual in unusual_combination:
|
global gcc_multilib_set
|
||||||
os = os_unusual
|
|
||||||
|
|
||||||
compilers = compilers_default
|
os = os_unusual if os_unusual in combination else os_default
|
||||||
if compilers_unusual in unusual_combination:
|
compilers = compilers_unusual if compilers_unusual in combination else compilers_default
|
||||||
compilers = compilers_unusual
|
|
||||||
|
|
||||||
compiler_flags = [
|
compiler_flags = [x for x in combination if x in compiler_flag_unusuals]
|
||||||
x for x in unusual_combination if x in compiler_flag_unusuals]
|
configure_flags = [x for x in combination if x in configure_flag_unusuals]
|
||||||
|
malloc_conf = [x for x in combination if x in malloc_conf_unusuals]
|
||||||
|
|
||||||
configure_flags = [
|
|
||||||
x for x in unusual_combination if x in configure_flag_unusuals]
|
|
||||||
|
|
||||||
malloc_conf = [
|
|
||||||
x for x in unusual_combination if x in malloc_conf_unusuals]
|
|
||||||
# Filter out unsupported configurations on OS X.
|
# Filter out unsupported configurations on OS X.
|
||||||
if os == 'osx' and ('dss:primary' in malloc_conf or \
|
if os == 'osx' and ('dss:primary' in malloc_conf or \
|
||||||
'percpu_arena:percpu' in malloc_conf or 'background_thread:true' \
|
'percpu_arena:percpu' in malloc_conf or 'background_thread:true' \
|
||||||
in malloc_conf):
|
in malloc_conf):
|
||||||
continue
|
return ""
|
||||||
if len(malloc_conf) > 0:
|
if len(malloc_conf) > 0:
|
||||||
configure_flags.append('--with-malloc-conf=' + ",".join(malloc_conf))
|
configure_flags.append('--with-malloc-conf=' + ",".join(malloc_conf))
|
||||||
|
|
||||||
# Filter out an unsupported configuration - heap profiling on OS X.
|
# Filter out an unsupported configuration - heap profiling on OS X.
|
||||||
if os == 'osx' and '--enable-prof' in configure_flags:
|
if os == 'osx' and '--enable-prof' in configure_flags:
|
||||||
continue
|
return ""
|
||||||
|
|
||||||
# We get some spurious errors when -Warray-bounds is enabled.
|
# We get some spurious errors when -Warray-bounds is enabled.
|
||||||
env_string = ('{} COMPILER_FLAGS="{}" CONFIGURE_FLAGS="{}" '
|
env_string = ('{} COMPILER_FLAGS="{}" CONFIGURE_FLAGS="{}" '
|
||||||
'EXTRA_CFLAGS="-Werror -Wno-array-bounds"').format(
|
'EXTRA_CFLAGS="-Werror -Wno-array-bounds"').format(
|
||||||
compilers, " ".join(compiler_flags), " ".join(configure_flags))
|
compilers, " ".join(compiler_flags), " ".join(configure_flags))
|
||||||
|
|
||||||
include_rows += ' - os: %s\n' % os
|
job = ""
|
||||||
include_rows += ' env: %s\n' % env_string
|
job += ' - os: %s\n' % os
|
||||||
if '-m32' in unusual_combination and os == 'linux':
|
job += ' env: %s\n' % env_string
|
||||||
include_rows += ' addons:\n'
|
if '-m32' in combination and os == 'linux':
|
||||||
include_rows += ' apt:\n'
|
job += ' addons:'
|
||||||
include_rows += ' packages:\n'
|
if gcc_multilib_set:
|
||||||
include_rows += ' - gcc-multilib\n'
|
job += ' *gcc_multilib\n'
|
||||||
|
else:
|
||||||
|
job += ' &gcc_multilib\n'
|
||||||
|
job += ' apt:\n'
|
||||||
|
job += ' packages:\n'
|
||||||
|
job += ' - gcc-multilib\n'
|
||||||
|
gcc_multilib_set = True
|
||||||
|
return job
|
||||||
|
|
||||||
|
include_rows = ""
|
||||||
|
for combination in unusual_combinations_to_test:
|
||||||
|
include_rows += format_job(combination)
|
||||||
|
|
||||||
|
# Development build
|
||||||
|
include_rows += '''\
|
||||||
|
# Development build
|
||||||
|
- os: linux
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-cache-oblivious --enable-stats --enable-log --enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
'''
|
||||||
|
|
||||||
|
# Enable-expermental-smallocx
|
||||||
|
include_rows += '''\
|
||||||
|
# --enable-expermental-smallocx:
|
||||||
|
- os: linux
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --enable-experimental-smallocx --enable-stats --enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
|
||||||
|
'''
|
||||||
|
|
||||||
|
# Valgrind build bots
|
||||||
|
include_rows += '''
|
||||||
|
# Valgrind
|
||||||
|
- os: linux
|
||||||
|
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" JEMALLOC_TEST_PREFIX="valgrind"
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- valgrind
|
||||||
|
'''
|
||||||
|
|
||||||
|
# To enable valgrind on macosx add:
|
||||||
|
#
|
||||||
|
# - os: osx
|
||||||
|
# env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" JEMALLOC_TEST_PREFIX="valgrind"
|
||||||
|
# install: brew install valgrind
|
||||||
|
#
|
||||||
|
# It currently fails due to: https://github.com/jemalloc/jemalloc/issues/1274
|
||||||
|
|
||||||
print travis_template % include_rows
|
print travis_template % include_rows
|
||||||
|
547
deps/jemalloc/src/arena.c
vendored
547
deps/jemalloc/src/arena.c
vendored
@ -8,9 +8,11 @@
|
|||||||
#include "jemalloc/internal/extent_mmap.h"
|
#include "jemalloc/internal/extent_mmap.h"
|
||||||
#include "jemalloc/internal/mutex.h"
|
#include "jemalloc/internal/mutex.h"
|
||||||
#include "jemalloc/internal/rtree.h"
|
#include "jemalloc/internal/rtree.h"
|
||||||
#include "jemalloc/internal/size_classes.h"
|
#include "jemalloc/internal/safety_check.h"
|
||||||
#include "jemalloc/internal/util.h"
|
#include "jemalloc/internal/util.h"
|
||||||
|
|
||||||
|
JEMALLOC_DIAGNOSTIC_DISABLE_SPURIOUS
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* Data. */
|
/* Data. */
|
||||||
|
|
||||||
@ -40,7 +42,11 @@ const uint64_t h_steps[SMOOTHSTEP_NSTEPS] = {
|
|||||||
#undef STEP
|
#undef STEP
|
||||||
};
|
};
|
||||||
|
|
||||||
static div_info_t arena_binind_div_info[NBINS];
|
static div_info_t arena_binind_div_info[SC_NBINS];
|
||||||
|
|
||||||
|
size_t opt_oversize_threshold = OVERSIZE_THRESHOLD_DEFAULT;
|
||||||
|
size_t oversize_threshold = OVERSIZE_THRESHOLD_DEFAULT;
|
||||||
|
static unsigned huge_arena_ind;
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/*
|
/*
|
||||||
@ -61,7 +67,7 @@ static void arena_bin_lower_slab(tsdn_t *tsdn, arena_t *arena, extent_t *slab,
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
void
|
void
|
||||||
arena_basic_stats_merge(UNUSED tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
||||||
const char **dss, ssize_t *dirty_decay_ms, ssize_t *muzzy_decay_ms,
|
const char **dss, ssize_t *dirty_decay_ms, ssize_t *muzzy_decay_ms,
|
||||||
size_t *nactive, size_t *ndirty, size_t *nmuzzy) {
|
size_t *nactive, size_t *ndirty, size_t *nmuzzy) {
|
||||||
*nthreads += arena_nthreads_get(arena, false);
|
*nthreads += arena_nthreads_get(arena, false);
|
||||||
@ -77,7 +83,8 @@ void
|
|||||||
arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
||||||
const char **dss, ssize_t *dirty_decay_ms, ssize_t *muzzy_decay_ms,
|
const char **dss, ssize_t *dirty_decay_ms, ssize_t *muzzy_decay_ms,
|
||||||
size_t *nactive, size_t *ndirty, size_t *nmuzzy, arena_stats_t *astats,
|
size_t *nactive, size_t *ndirty, size_t *nmuzzy, arena_stats_t *astats,
|
||||||
bin_stats_t *bstats, arena_stats_large_t *lstats) {
|
bin_stats_t *bstats, arena_stats_large_t *lstats,
|
||||||
|
arena_stats_extents_t *estats) {
|
||||||
cassert(config_stats);
|
cassert(config_stats);
|
||||||
|
|
||||||
arena_basic_stats_merge(tsdn, arena, nthreads, dss, dirty_decay_ms,
|
arena_basic_stats_merge(tsdn, arena, nthreads, dss, dirty_decay_ms,
|
||||||
@ -94,6 +101,10 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
|||||||
arena_stats_accum_zu(&astats->retained,
|
arena_stats_accum_zu(&astats->retained,
|
||||||
extents_npages_get(&arena->extents_retained) << LG_PAGE);
|
extents_npages_get(&arena->extents_retained) << LG_PAGE);
|
||||||
|
|
||||||
|
atomic_store_zu(&astats->extent_avail,
|
||||||
|
atomic_load_zu(&arena->extent_avail_cnt, ATOMIC_RELAXED),
|
||||||
|
ATOMIC_RELAXED);
|
||||||
|
|
||||||
arena_stats_accum_u64(&astats->decay_dirty.npurge,
|
arena_stats_accum_u64(&astats->decay_dirty.npurge,
|
||||||
arena_stats_read_u64(tsdn, &arena->stats,
|
arena_stats_read_u64(tsdn, &arena->stats,
|
||||||
&arena->stats.decay_dirty.npurge));
|
&arena->stats.decay_dirty.npurge));
|
||||||
@ -121,8 +132,10 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
|||||||
(((atomic_load_zu(&arena->nactive, ATOMIC_RELAXED) +
|
(((atomic_load_zu(&arena->nactive, ATOMIC_RELAXED) +
|
||||||
extents_npages_get(&arena->extents_dirty) +
|
extents_npages_get(&arena->extents_dirty) +
|
||||||
extents_npages_get(&arena->extents_muzzy)) << LG_PAGE)));
|
extents_npages_get(&arena->extents_muzzy)) << LG_PAGE)));
|
||||||
|
arena_stats_accum_zu(&astats->abandoned_vm, atomic_load_zu(
|
||||||
|
&arena->stats.abandoned_vm, ATOMIC_RELAXED));
|
||||||
|
|
||||||
for (szind_t i = 0; i < NSIZES - NBINS; i++) {
|
for (szind_t i = 0; i < SC_NSIZES - SC_NBINS; i++) {
|
||||||
uint64_t nmalloc = arena_stats_read_u64(tsdn, &arena->stats,
|
uint64_t nmalloc = arena_stats_read_u64(tsdn, &arena->stats,
|
||||||
&arena->stats.lstats[i].nmalloc);
|
&arena->stats.lstats[i].nmalloc);
|
||||||
arena_stats_accum_u64(&lstats[i].nmalloc, nmalloc);
|
arena_stats_accum_u64(&lstats[i].nmalloc, nmalloc);
|
||||||
@ -140,12 +153,43 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
|||||||
arena_stats_accum_u64(&astats->nrequests_large,
|
arena_stats_accum_u64(&astats->nrequests_large,
|
||||||
nmalloc + nrequests);
|
nmalloc + nrequests);
|
||||||
|
|
||||||
|
/* nfill == nmalloc for large currently. */
|
||||||
|
arena_stats_accum_u64(&lstats[i].nfills, nmalloc);
|
||||||
|
arena_stats_accum_u64(&astats->nfills_large, nmalloc);
|
||||||
|
|
||||||
|
uint64_t nflush = arena_stats_read_u64(tsdn, &arena->stats,
|
||||||
|
&arena->stats.lstats[i].nflushes);
|
||||||
|
arena_stats_accum_u64(&lstats[i].nflushes, nflush);
|
||||||
|
arena_stats_accum_u64(&astats->nflushes_large, nflush);
|
||||||
|
|
||||||
assert(nmalloc >= ndalloc);
|
assert(nmalloc >= ndalloc);
|
||||||
assert(nmalloc - ndalloc <= SIZE_T_MAX);
|
assert(nmalloc - ndalloc <= SIZE_T_MAX);
|
||||||
size_t curlextents = (size_t)(nmalloc - ndalloc);
|
size_t curlextents = (size_t)(nmalloc - ndalloc);
|
||||||
lstats[i].curlextents += curlextents;
|
lstats[i].curlextents += curlextents;
|
||||||
arena_stats_accum_zu(&astats->allocated_large,
|
arena_stats_accum_zu(&astats->allocated_large,
|
||||||
curlextents * sz_index2size(NBINS + i));
|
curlextents * sz_index2size(SC_NBINS + i));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (pszind_t i = 0; i < SC_NPSIZES; i++) {
|
||||||
|
size_t dirty, muzzy, retained, dirty_bytes, muzzy_bytes,
|
||||||
|
retained_bytes;
|
||||||
|
dirty = extents_nextents_get(&arena->extents_dirty, i);
|
||||||
|
muzzy = extents_nextents_get(&arena->extents_muzzy, i);
|
||||||
|
retained = extents_nextents_get(&arena->extents_retained, i);
|
||||||
|
dirty_bytes = extents_nbytes_get(&arena->extents_dirty, i);
|
||||||
|
muzzy_bytes = extents_nbytes_get(&arena->extents_muzzy, i);
|
||||||
|
retained_bytes =
|
||||||
|
extents_nbytes_get(&arena->extents_retained, i);
|
||||||
|
|
||||||
|
atomic_store_zu(&estats[i].ndirty, dirty, ATOMIC_RELAXED);
|
||||||
|
atomic_store_zu(&estats[i].nmuzzy, muzzy, ATOMIC_RELAXED);
|
||||||
|
atomic_store_zu(&estats[i].nretained, retained, ATOMIC_RELAXED);
|
||||||
|
atomic_store_zu(&estats[i].dirty_bytes, dirty_bytes,
|
||||||
|
ATOMIC_RELAXED);
|
||||||
|
atomic_store_zu(&estats[i].muzzy_bytes, muzzy_bytes,
|
||||||
|
ATOMIC_RELAXED);
|
||||||
|
atomic_store_zu(&estats[i].retained_bytes, retained_bytes,
|
||||||
|
ATOMIC_RELAXED);
|
||||||
}
|
}
|
||||||
|
|
||||||
arena_stats_unlock(tsdn, &arena->stats);
|
arena_stats_unlock(tsdn, &arena->stats);
|
||||||
@ -156,7 +200,7 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
|||||||
cache_bin_array_descriptor_t *descriptor;
|
cache_bin_array_descriptor_t *descriptor;
|
||||||
ql_foreach(descriptor, &arena->cache_bin_array_descriptor_ql, link) {
|
ql_foreach(descriptor, &arena->cache_bin_array_descriptor_ql, link) {
|
||||||
szind_t i = 0;
|
szind_t i = 0;
|
||||||
for (; i < NBINS; i++) {
|
for (; i < SC_NBINS; i++) {
|
||||||
cache_bin_t *tbin = &descriptor->bins_small[i];
|
cache_bin_t *tbin = &descriptor->bins_small[i];
|
||||||
arena_stats_accum_zu(&astats->tcache_bytes,
|
arena_stats_accum_zu(&astats->tcache_bytes,
|
||||||
tbin->ncached * sz_index2size(i));
|
tbin->ncached * sz_index2size(i));
|
||||||
@ -200,8 +244,11 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
|||||||
nstime_update(&astats->uptime);
|
nstime_update(&astats->uptime);
|
||||||
nstime_subtract(&astats->uptime, &arena->create_time);
|
nstime_subtract(&astats->uptime, &arena->create_time);
|
||||||
|
|
||||||
for (szind_t i = 0; i < NBINS; i++) {
|
for (szind_t i = 0; i < SC_NBINS; i++) {
|
||||||
bin_stats_merge(tsdn, &bstats[i], &arena->bins[i]);
|
for (unsigned j = 0; j < bin_infos[i].n_shards; j++) {
|
||||||
|
bin_stats_merge(tsdn, &bstats[i],
|
||||||
|
&arena->bins[i].bin_shards[j]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,6 +283,54 @@ arena_slab_reg_alloc(extent_t *slab, const bin_info_t *bin_info) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
arena_slab_reg_alloc_batch(extent_t *slab, const bin_info_t *bin_info,
|
||||||
|
unsigned cnt, void** ptrs) {
|
||||||
|
arena_slab_data_t *slab_data = extent_slab_data_get(slab);
|
||||||
|
|
||||||
|
assert(extent_nfree_get(slab) >= cnt);
|
||||||
|
assert(!bitmap_full(slab_data->bitmap, &bin_info->bitmap_info));
|
||||||
|
|
||||||
|
#if (! defined JEMALLOC_INTERNAL_POPCOUNTL) || (defined BITMAP_USE_TREE)
|
||||||
|
for (unsigned i = 0; i < cnt; i++) {
|
||||||
|
size_t regind = bitmap_sfu(slab_data->bitmap,
|
||||||
|
&bin_info->bitmap_info);
|
||||||
|
*(ptrs + i) = (void *)((uintptr_t)extent_addr_get(slab) +
|
||||||
|
(uintptr_t)(bin_info->reg_size * regind));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
unsigned group = 0;
|
||||||
|
bitmap_t g = slab_data->bitmap[group];
|
||||||
|
unsigned i = 0;
|
||||||
|
while (i < cnt) {
|
||||||
|
while (g == 0) {
|
||||||
|
g = slab_data->bitmap[++group];
|
||||||
|
}
|
||||||
|
size_t shift = group << LG_BITMAP_GROUP_NBITS;
|
||||||
|
size_t pop = popcount_lu(g);
|
||||||
|
if (pop > (cnt - i)) {
|
||||||
|
pop = cnt - i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load from memory locations only once, outside the
|
||||||
|
* hot loop below.
|
||||||
|
*/
|
||||||
|
uintptr_t base = (uintptr_t)extent_addr_get(slab);
|
||||||
|
uintptr_t regsize = (uintptr_t)bin_info->reg_size;
|
||||||
|
while (pop--) {
|
||||||
|
size_t bit = cfs_lu(&g);
|
||||||
|
size_t regind = shift + bit;
|
||||||
|
*(ptrs + i) = (void *)(base + regsize * regind);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
slab_data->bitmap[group] = g;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
extent_nfree_sub(slab, cnt);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef JEMALLOC_JET
|
#ifndef JEMALLOC_JET
|
||||||
static
|
static
|
||||||
#endif
|
#endif
|
||||||
@ -291,11 +386,11 @@ arena_large_malloc_stats_update(tsdn_t *tsdn, arena_t *arena, size_t usize) {
|
|||||||
|
|
||||||
cassert(config_stats);
|
cassert(config_stats);
|
||||||
|
|
||||||
if (usize < LARGE_MINCLASS) {
|
if (usize < SC_LARGE_MINCLASS) {
|
||||||
usize = LARGE_MINCLASS;
|
usize = SC_LARGE_MINCLASS;
|
||||||
}
|
}
|
||||||
index = sz_size2index(usize);
|
index = sz_size2index(usize);
|
||||||
hindex = (index >= NBINS) ? index - NBINS : 0;
|
hindex = (index >= SC_NBINS) ? index - SC_NBINS : 0;
|
||||||
|
|
||||||
arena_stats_add_u64(tsdn, &arena->stats,
|
arena_stats_add_u64(tsdn, &arena->stats,
|
||||||
&arena->stats.lstats[hindex].nmalloc, 1);
|
&arena->stats.lstats[hindex].nmalloc, 1);
|
||||||
@ -307,11 +402,11 @@ arena_large_dalloc_stats_update(tsdn_t *tsdn, arena_t *arena, size_t usize) {
|
|||||||
|
|
||||||
cassert(config_stats);
|
cassert(config_stats);
|
||||||
|
|
||||||
if (usize < LARGE_MINCLASS) {
|
if (usize < SC_LARGE_MINCLASS) {
|
||||||
usize = LARGE_MINCLASS;
|
usize = SC_LARGE_MINCLASS;
|
||||||
}
|
}
|
||||||
index = sz_size2index(usize);
|
index = sz_size2index(usize);
|
||||||
hindex = (index >= NBINS) ? index - NBINS : 0;
|
hindex = (index >= SC_NBINS) ? index - SC_NBINS : 0;
|
||||||
|
|
||||||
arena_stats_add_u64(tsdn, &arena->stats,
|
arena_stats_add_u64(tsdn, &arena->stats,
|
||||||
&arena->stats.lstats[hindex].ndalloc, 1);
|
&arena->stats.lstats[hindex].ndalloc, 1);
|
||||||
@ -324,6 +419,11 @@ arena_large_ralloc_stats_update(tsdn_t *tsdn, arena_t *arena, size_t oldusize,
|
|||||||
arena_large_malloc_stats_update(tsdn, arena, usize);
|
arena_large_malloc_stats_update(tsdn, arena, usize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
arena_may_have_muzzy(arena_t *arena) {
|
||||||
|
return (pages_can_purge_lazy && (arena_muzzy_decay_ms_get(arena) != 0));
|
||||||
|
}
|
||||||
|
|
||||||
extent_t *
|
extent_t *
|
||||||
arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize,
|
arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize,
|
||||||
size_t alignment, bool *zero) {
|
size_t alignment, bool *zero) {
|
||||||
@ -338,7 +438,7 @@ arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize,
|
|||||||
extent_t *extent = extents_alloc(tsdn, arena, &extent_hooks,
|
extent_t *extent = extents_alloc(tsdn, arena, &extent_hooks,
|
||||||
&arena->extents_dirty, NULL, usize, sz_large_pad, alignment, false,
|
&arena->extents_dirty, NULL, usize, sz_large_pad, alignment, false,
|
||||||
szind, zero, &commit);
|
szind, zero, &commit);
|
||||||
if (extent == NULL) {
|
if (extent == NULL && arena_may_have_muzzy(arena)) {
|
||||||
extent = extents_alloc(tsdn, arena, &extent_hooks,
|
extent = extents_alloc(tsdn, arena, &extent_hooks,
|
||||||
&arena->extents_muzzy, NULL, usize, sz_large_pad, alignment,
|
&arena->extents_muzzy, NULL, usize, sz_large_pad, alignment,
|
||||||
false, szind, zero, &commit);
|
false, szind, zero, &commit);
|
||||||
@ -743,7 +843,7 @@ static size_t
|
|||||||
arena_decay_stashed(tsdn_t *tsdn, arena_t *arena,
|
arena_decay_stashed(tsdn_t *tsdn, arena_t *arena,
|
||||||
extent_hooks_t **r_extent_hooks, arena_decay_t *decay, extents_t *extents,
|
extent_hooks_t **r_extent_hooks, arena_decay_t *decay, extents_t *extents,
|
||||||
bool all, extent_list_t *decay_extents, bool is_background_thread) {
|
bool all, extent_list_t *decay_extents, bool is_background_thread) {
|
||||||
UNUSED size_t nmadvise, nunmapped;
|
size_t nmadvise, nunmapped;
|
||||||
size_t npurged;
|
size_t npurged;
|
||||||
|
|
||||||
if (config_stats) {
|
if (config_stats) {
|
||||||
@ -834,7 +934,7 @@ arena_decay_to_limit(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay,
|
|||||||
size_t npurge = arena_stash_decayed(tsdn, arena, &extent_hooks, extents,
|
size_t npurge = arena_stash_decayed(tsdn, arena, &extent_hooks, extents,
|
||||||
npages_limit, npages_decay_max, &decay_extents);
|
npages_limit, npages_decay_max, &decay_extents);
|
||||||
if (npurge != 0) {
|
if (npurge != 0) {
|
||||||
UNUSED size_t npurged = arena_decay_stashed(tsdn, arena,
|
size_t npurged = arena_decay_stashed(tsdn, arena,
|
||||||
&extent_hooks, decay, extents, all, &decay_extents,
|
&extent_hooks, decay, extents, all, &decay_extents,
|
||||||
is_background_thread);
|
is_background_thread);
|
||||||
assert(npurged == npurge);
|
assert(npurged == npurge);
|
||||||
@ -863,7 +963,7 @@ arena_decay_impl(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay,
|
|||||||
|
|
||||||
bool epoch_advanced = arena_maybe_decay(tsdn, arena, decay, extents,
|
bool epoch_advanced = arena_maybe_decay(tsdn, arena, decay, extents,
|
||||||
is_background_thread);
|
is_background_thread);
|
||||||
UNUSED size_t npages_new;
|
size_t npages_new;
|
||||||
if (epoch_advanced) {
|
if (epoch_advanced) {
|
||||||
/* Backlog is updated on epoch advance. */
|
/* Backlog is updated on epoch advance. */
|
||||||
npages_new = decay->backlog[SMOOTHSTEP_NSTEPS-1];
|
npages_new = decay->backlog[SMOOTHSTEP_NSTEPS-1];
|
||||||
@ -913,11 +1013,17 @@ static void
|
|||||||
arena_bin_slabs_nonfull_insert(bin_t *bin, extent_t *slab) {
|
arena_bin_slabs_nonfull_insert(bin_t *bin, extent_t *slab) {
|
||||||
assert(extent_nfree_get(slab) > 0);
|
assert(extent_nfree_get(slab) > 0);
|
||||||
extent_heap_insert(&bin->slabs_nonfull, slab);
|
extent_heap_insert(&bin->slabs_nonfull, slab);
|
||||||
|
if (config_stats) {
|
||||||
|
bin->stats.nonfull_slabs++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
arena_bin_slabs_nonfull_remove(bin_t *bin, extent_t *slab) {
|
arena_bin_slabs_nonfull_remove(bin_t *bin, extent_t *slab) {
|
||||||
extent_heap_remove(&bin->slabs_nonfull, slab);
|
extent_heap_remove(&bin->slabs_nonfull, slab);
|
||||||
|
if (config_stats) {
|
||||||
|
bin->stats.nonfull_slabs--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static extent_t *
|
static extent_t *
|
||||||
@ -928,6 +1034,7 @@ arena_bin_slabs_nonfull_tryget(bin_t *bin) {
|
|||||||
}
|
}
|
||||||
if (config_stats) {
|
if (config_stats) {
|
||||||
bin->stats.reslabs++;
|
bin->stats.reslabs++;
|
||||||
|
bin->stats.nonfull_slabs--;
|
||||||
}
|
}
|
||||||
return slab;
|
return slab;
|
||||||
}
|
}
|
||||||
@ -954,6 +1061,37 @@ arena_bin_slabs_full_remove(arena_t *arena, bin_t *bin, extent_t *slab) {
|
|||||||
extent_list_remove(&bin->slabs_full, slab);
|
extent_list_remove(&bin->slabs_full, slab);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
arena_bin_reset(tsd_t *tsd, arena_t *arena, bin_t *bin) {
|
||||||
|
extent_t *slab;
|
||||||
|
|
||||||
|
malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock);
|
||||||
|
if (bin->slabcur != NULL) {
|
||||||
|
slab = bin->slabcur;
|
||||||
|
bin->slabcur = NULL;
|
||||||
|
malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock);
|
||||||
|
arena_slab_dalloc(tsd_tsdn(tsd), arena, slab);
|
||||||
|
malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock);
|
||||||
|
}
|
||||||
|
while ((slab = extent_heap_remove_first(&bin->slabs_nonfull)) != NULL) {
|
||||||
|
malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock);
|
||||||
|
arena_slab_dalloc(tsd_tsdn(tsd), arena, slab);
|
||||||
|
malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock);
|
||||||
|
}
|
||||||
|
for (slab = extent_list_first(&bin->slabs_full); slab != NULL;
|
||||||
|
slab = extent_list_first(&bin->slabs_full)) {
|
||||||
|
arena_bin_slabs_full_remove(arena, bin, slab);
|
||||||
|
malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock);
|
||||||
|
arena_slab_dalloc(tsd_tsdn(tsd), arena, slab);
|
||||||
|
malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock);
|
||||||
|
}
|
||||||
|
if (config_stats) {
|
||||||
|
bin->stats.curregs = 0;
|
||||||
|
bin->stats.curslabs = 0;
|
||||||
|
}
|
||||||
|
malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
arena_reset(tsd_t *tsd, arena_t *arena) {
|
arena_reset(tsd_t *tsd, arena_t *arena) {
|
||||||
/*
|
/*
|
||||||
@ -983,7 +1121,7 @@ arena_reset(tsd_t *tsd, arena_t *arena) {
|
|||||||
rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd);
|
rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd);
|
||||||
rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx,
|
rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx,
|
||||||
(uintptr_t)ptr, true, &alloc_ctx.szind, &alloc_ctx.slab);
|
(uintptr_t)ptr, true, &alloc_ctx.szind, &alloc_ctx.slab);
|
||||||
assert(alloc_ctx.szind != NSIZES);
|
assert(alloc_ctx.szind != SC_NSIZES);
|
||||||
|
|
||||||
if (config_stats || (config_prof && opt_prof)) {
|
if (config_stats || (config_prof && opt_prof)) {
|
||||||
usize = sz_index2size(alloc_ctx.szind);
|
usize = sz_index2size(alloc_ctx.szind);
|
||||||
@ -999,35 +1137,11 @@ arena_reset(tsd_t *tsd, arena_t *arena) {
|
|||||||
malloc_mutex_unlock(tsd_tsdn(tsd), &arena->large_mtx);
|
malloc_mutex_unlock(tsd_tsdn(tsd), &arena->large_mtx);
|
||||||
|
|
||||||
/* Bins. */
|
/* Bins. */
|
||||||
for (unsigned i = 0; i < NBINS; i++) {
|
for (unsigned i = 0; i < SC_NBINS; i++) {
|
||||||
extent_t *slab;
|
for (unsigned j = 0; j < bin_infos[i].n_shards; j++) {
|
||||||
bin_t *bin = &arena->bins[i];
|
arena_bin_reset(tsd, arena,
|
||||||
malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock);
|
&arena->bins[i].bin_shards[j]);
|
||||||
if (bin->slabcur != NULL) {
|
|
||||||
slab = bin->slabcur;
|
|
||||||
bin->slabcur = NULL;
|
|
||||||
malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock);
|
|
||||||
arena_slab_dalloc(tsd_tsdn(tsd), arena, slab);
|
|
||||||
malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock);
|
|
||||||
}
|
}
|
||||||
while ((slab = extent_heap_remove_first(&bin->slabs_nonfull)) !=
|
|
||||||
NULL) {
|
|
||||||
malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock);
|
|
||||||
arena_slab_dalloc(tsd_tsdn(tsd), arena, slab);
|
|
||||||
malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock);
|
|
||||||
}
|
|
||||||
for (slab = extent_list_first(&bin->slabs_full); slab != NULL;
|
|
||||||
slab = extent_list_first(&bin->slabs_full)) {
|
|
||||||
arena_bin_slabs_full_remove(arena, bin, slab);
|
|
||||||
malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock);
|
|
||||||
arena_slab_dalloc(tsd_tsdn(tsd), arena, slab);
|
|
||||||
malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock);
|
|
||||||
}
|
|
||||||
if (config_stats) {
|
|
||||||
bin->stats.curregs = 0;
|
|
||||||
bin->stats.curslabs = 0;
|
|
||||||
}
|
|
||||||
malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_store_zu(&arena->nactive, 0, ATOMIC_RELAXED);
|
atomic_store_zu(&arena->nactive, 0, ATOMIC_RELAXED);
|
||||||
@ -1112,7 +1226,7 @@ arena_slab_alloc_hard(tsdn_t *tsdn, arena_t *arena,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static extent_t *
|
static extent_t *
|
||||||
arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind,
|
arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, unsigned binshard,
|
||||||
const bin_info_t *bin_info) {
|
const bin_info_t *bin_info) {
|
||||||
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
||||||
WITNESS_RANK_CORE, 0);
|
WITNESS_RANK_CORE, 0);
|
||||||
@ -1124,7 +1238,7 @@ arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind,
|
|||||||
extent_t *slab = extents_alloc(tsdn, arena, &extent_hooks,
|
extent_t *slab = extents_alloc(tsdn, arena, &extent_hooks,
|
||||||
&arena->extents_dirty, NULL, bin_info->slab_size, 0, PAGE, true,
|
&arena->extents_dirty, NULL, bin_info->slab_size, 0, PAGE, true,
|
||||||
binind, &zero, &commit);
|
binind, &zero, &commit);
|
||||||
if (slab == NULL) {
|
if (slab == NULL && arena_may_have_muzzy(arena)) {
|
||||||
slab = extents_alloc(tsdn, arena, &extent_hooks,
|
slab = extents_alloc(tsdn, arena, &extent_hooks,
|
||||||
&arena->extents_muzzy, NULL, bin_info->slab_size, 0, PAGE,
|
&arena->extents_muzzy, NULL, bin_info->slab_size, 0, PAGE,
|
||||||
true, binind, &zero, &commit);
|
true, binind, &zero, &commit);
|
||||||
@ -1140,7 +1254,7 @@ arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind,
|
|||||||
|
|
||||||
/* Initialize slab internals. */
|
/* Initialize slab internals. */
|
||||||
arena_slab_data_t *slab_data = extent_slab_data_get(slab);
|
arena_slab_data_t *slab_data = extent_slab_data_get(slab);
|
||||||
extent_nfree_set(slab, bin_info->nregs);
|
extent_nfree_binshard_set(slab, bin_info->nregs, binshard);
|
||||||
bitmap_init(slab_data->bitmap, &bin_info->bitmap_info, false);
|
bitmap_init(slab_data->bitmap, &bin_info->bitmap_info, false);
|
||||||
|
|
||||||
arena_nactive_add(arena, extent_size_get(slab) >> LG_PAGE);
|
arena_nactive_add(arena, extent_size_get(slab) >> LG_PAGE);
|
||||||
@ -1150,7 +1264,7 @@ arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind,
|
|||||||
|
|
||||||
static extent_t *
|
static extent_t *
|
||||||
arena_bin_nonfull_slab_get(tsdn_t *tsdn, arena_t *arena, bin_t *bin,
|
arena_bin_nonfull_slab_get(tsdn_t *tsdn, arena_t *arena, bin_t *bin,
|
||||||
szind_t binind) {
|
szind_t binind, unsigned binshard) {
|
||||||
extent_t *slab;
|
extent_t *slab;
|
||||||
const bin_info_t *bin_info;
|
const bin_info_t *bin_info;
|
||||||
|
|
||||||
@ -1166,7 +1280,7 @@ arena_bin_nonfull_slab_get(tsdn_t *tsdn, arena_t *arena, bin_t *bin,
|
|||||||
/* Allocate a new slab. */
|
/* Allocate a new slab. */
|
||||||
malloc_mutex_unlock(tsdn, &bin->lock);
|
malloc_mutex_unlock(tsdn, &bin->lock);
|
||||||
/******************************/
|
/******************************/
|
||||||
slab = arena_slab_alloc(tsdn, arena, binind, bin_info);
|
slab = arena_slab_alloc(tsdn, arena, binind, binshard, bin_info);
|
||||||
/********************************/
|
/********************************/
|
||||||
malloc_mutex_lock(tsdn, &bin->lock);
|
malloc_mutex_lock(tsdn, &bin->lock);
|
||||||
if (slab != NULL) {
|
if (slab != NULL) {
|
||||||
@ -1193,7 +1307,7 @@ arena_bin_nonfull_slab_get(tsdn_t *tsdn, arena_t *arena, bin_t *bin,
|
|||||||
/* Re-fill bin->slabcur, then call arena_slab_reg_alloc(). */
|
/* Re-fill bin->slabcur, then call arena_slab_reg_alloc(). */
|
||||||
static void *
|
static void *
|
||||||
arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, bin_t *bin,
|
arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, bin_t *bin,
|
||||||
szind_t binind) {
|
szind_t binind, unsigned binshard) {
|
||||||
const bin_info_t *bin_info;
|
const bin_info_t *bin_info;
|
||||||
extent_t *slab;
|
extent_t *slab;
|
||||||
|
|
||||||
@ -1202,7 +1316,7 @@ arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, bin_t *bin,
|
|||||||
arena_bin_slabs_full_insert(arena, bin, bin->slabcur);
|
arena_bin_slabs_full_insert(arena, bin, bin->slabcur);
|
||||||
bin->slabcur = NULL;
|
bin->slabcur = NULL;
|
||||||
}
|
}
|
||||||
slab = arena_bin_nonfull_slab_get(tsdn, arena, bin, binind);
|
slab = arena_bin_nonfull_slab_get(tsdn, arena, bin, binind, binshard);
|
||||||
if (bin->slabcur != NULL) {
|
if (bin->slabcur != NULL) {
|
||||||
/*
|
/*
|
||||||
* Another thread updated slabcur while this one ran without the
|
* Another thread updated slabcur while this one ran without the
|
||||||
@ -1246,47 +1360,76 @@ arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, bin_t *bin,
|
|||||||
return arena_slab_reg_alloc(slab, bin_info);
|
return arena_slab_reg_alloc(slab, bin_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Choose a bin shard and return the locked bin. */
|
||||||
|
bin_t *
|
||||||
|
arena_bin_choose_lock(tsdn_t *tsdn, arena_t *arena, szind_t binind,
|
||||||
|
unsigned *binshard) {
|
||||||
|
bin_t *bin;
|
||||||
|
if (tsdn_null(tsdn) || tsd_arena_get(tsdn_tsd(tsdn)) == NULL) {
|
||||||
|
*binshard = 0;
|
||||||
|
} else {
|
||||||
|
*binshard = tsd_binshardsp_get(tsdn_tsd(tsdn))->binshard[binind];
|
||||||
|
}
|
||||||
|
assert(*binshard < bin_infos[binind].n_shards);
|
||||||
|
bin = &arena->bins[binind].bin_shards[*binshard];
|
||||||
|
malloc_mutex_lock(tsdn, &bin->lock);
|
||||||
|
|
||||||
|
return bin;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache,
|
arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache,
|
||||||
cache_bin_t *tbin, szind_t binind, uint64_t prof_accumbytes) {
|
cache_bin_t *tbin, szind_t binind, uint64_t prof_accumbytes) {
|
||||||
unsigned i, nfill;
|
unsigned i, nfill, cnt;
|
||||||
bin_t *bin;
|
|
||||||
|
|
||||||
assert(tbin->ncached == 0);
|
assert(tbin->ncached == 0);
|
||||||
|
|
||||||
if (config_prof && arena_prof_accum(tsdn, arena, prof_accumbytes)) {
|
if (config_prof && arena_prof_accum(tsdn, arena, prof_accumbytes)) {
|
||||||
prof_idump(tsdn);
|
prof_idump(tsdn);
|
||||||
}
|
}
|
||||||
bin = &arena->bins[binind];
|
|
||||||
malloc_mutex_lock(tsdn, &bin->lock);
|
unsigned binshard;
|
||||||
|
bin_t *bin = arena_bin_choose_lock(tsdn, arena, binind, &binshard);
|
||||||
|
|
||||||
for (i = 0, nfill = (tcache_bin_info[binind].ncached_max >>
|
for (i = 0, nfill = (tcache_bin_info[binind].ncached_max >>
|
||||||
tcache->lg_fill_div[binind]); i < nfill; i++) {
|
tcache->lg_fill_div[binind]); i < nfill; i += cnt) {
|
||||||
extent_t *slab;
|
extent_t *slab;
|
||||||
void *ptr;
|
|
||||||
if ((slab = bin->slabcur) != NULL && extent_nfree_get(slab) >
|
if ((slab = bin->slabcur) != NULL && extent_nfree_get(slab) >
|
||||||
0) {
|
0) {
|
||||||
ptr = arena_slab_reg_alloc(slab, &bin_infos[binind]);
|
unsigned tofill = nfill - i;
|
||||||
|
cnt = tofill < extent_nfree_get(slab) ?
|
||||||
|
tofill : extent_nfree_get(slab);
|
||||||
|
arena_slab_reg_alloc_batch(
|
||||||
|
slab, &bin_infos[binind], cnt,
|
||||||
|
tbin->avail - nfill + i);
|
||||||
} else {
|
} else {
|
||||||
ptr = arena_bin_malloc_hard(tsdn, arena, bin, binind);
|
cnt = 1;
|
||||||
}
|
void *ptr = arena_bin_malloc_hard(tsdn, arena, bin,
|
||||||
if (ptr == NULL) {
|
binind, binshard);
|
||||||
/*
|
/*
|
||||||
* OOM. tbin->avail isn't yet filled down to its first
|
* OOM. tbin->avail isn't yet filled down to its first
|
||||||
* element, so the successful allocations (if any) must
|
* element, so the successful allocations (if any) must
|
||||||
* be moved just before tbin->avail before bailing out.
|
* be moved just before tbin->avail before bailing out.
|
||||||
*/
|
*/
|
||||||
|
if (ptr == NULL) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
memmove(tbin->avail - i, tbin->avail - nfill,
|
memmove(tbin->avail - i,
|
||||||
|
tbin->avail - nfill,
|
||||||
i * sizeof(void *));
|
i * sizeof(void *));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (config_fill && unlikely(opt_junk_alloc)) {
|
|
||||||
arena_alloc_junk_small(ptr, &bin_infos[binind], true);
|
|
||||||
}
|
|
||||||
/* Insert such that low regions get used first. */
|
/* Insert such that low regions get used first. */
|
||||||
*(tbin->avail - nfill + i) = ptr;
|
*(tbin->avail - nfill + i) = ptr;
|
||||||
}
|
}
|
||||||
|
if (config_fill && unlikely(opt_junk_alloc)) {
|
||||||
|
for (unsigned j = 0; j < cnt; j++) {
|
||||||
|
void* ptr = *(tbin->avail - nfill + i + j);
|
||||||
|
arena_alloc_junk_small(ptr, &bin_infos[binind],
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (config_stats) {
|
if (config_stats) {
|
||||||
bin->stats.nmalloc += i;
|
bin->stats.nmalloc += i;
|
||||||
bin->stats.nrequests += tbin->tstats.nrequests;
|
bin->stats.nrequests += tbin->tstats.nrequests;
|
||||||
@ -1320,15 +1463,15 @@ arena_malloc_small(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) {
|
|||||||
size_t usize;
|
size_t usize;
|
||||||
extent_t *slab;
|
extent_t *slab;
|
||||||
|
|
||||||
assert(binind < NBINS);
|
assert(binind < SC_NBINS);
|
||||||
bin = &arena->bins[binind];
|
|
||||||
usize = sz_index2size(binind);
|
usize = sz_index2size(binind);
|
||||||
|
unsigned binshard;
|
||||||
|
bin = arena_bin_choose_lock(tsdn, arena, binind, &binshard);
|
||||||
|
|
||||||
malloc_mutex_lock(tsdn, &bin->lock);
|
|
||||||
if ((slab = bin->slabcur) != NULL && extent_nfree_get(slab) > 0) {
|
if ((slab = bin->slabcur) != NULL && extent_nfree_get(slab) > 0) {
|
||||||
ret = arena_slab_reg_alloc(slab, &bin_infos[binind]);
|
ret = arena_slab_reg_alloc(slab, &bin_infos[binind]);
|
||||||
} else {
|
} else {
|
||||||
ret = arena_bin_malloc_hard(tsdn, arena, bin, binind);
|
ret = arena_bin_malloc_hard(tsdn, arena, bin, binind, binshard);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == NULL) {
|
if (ret == NULL) {
|
||||||
@ -1373,13 +1516,13 @@ arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind,
|
|||||||
assert(!tsdn_null(tsdn) || arena != NULL);
|
assert(!tsdn_null(tsdn) || arena != NULL);
|
||||||
|
|
||||||
if (likely(!tsdn_null(tsdn))) {
|
if (likely(!tsdn_null(tsdn))) {
|
||||||
arena = arena_choose(tsdn_tsd(tsdn), arena);
|
arena = arena_choose_maybe_huge(tsdn_tsd(tsdn), arena, size);
|
||||||
}
|
}
|
||||||
if (unlikely(arena == NULL)) {
|
if (unlikely(arena == NULL)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (likely(size <= SMALL_MAXCLASS)) {
|
if (likely(size <= SC_SMALL_MAXCLASS)) {
|
||||||
return arena_malloc_small(tsdn, arena, ind, zero);
|
return arena_malloc_small(tsdn, arena, ind, zero);
|
||||||
}
|
}
|
||||||
return large_malloc(tsdn, arena, sz_index2size(ind), zero);
|
return large_malloc(tsdn, arena, sz_index2size(ind), zero);
|
||||||
@ -1390,8 +1533,9 @@ arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment,
|
|||||||
bool zero, tcache_t *tcache) {
|
bool zero, tcache_t *tcache) {
|
||||||
void *ret;
|
void *ret;
|
||||||
|
|
||||||
if (usize <= SMALL_MAXCLASS && (alignment < PAGE || (alignment == PAGE
|
if (usize <= SC_SMALL_MAXCLASS
|
||||||
&& (usize & PAGE_MASK) == 0))) {
|
&& (alignment < PAGE
|
||||||
|
|| (alignment == PAGE && (usize & PAGE_MASK) == 0))) {
|
||||||
/* Small; alignment doesn't require special slab placement. */
|
/* Small; alignment doesn't require special slab placement. */
|
||||||
ret = arena_malloc(tsdn, arena, usize, sz_size2index(usize),
|
ret = arena_malloc(tsdn, arena, usize, sz_size2index(usize),
|
||||||
zero, tcache, true);
|
zero, tcache, true);
|
||||||
@ -1406,11 +1550,15 @@ arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
arena_prof_promote(tsdn_t *tsdn, const void *ptr, size_t usize) {
|
arena_prof_promote(tsdn_t *tsdn, void *ptr, size_t usize) {
|
||||||
cassert(config_prof);
|
cassert(config_prof);
|
||||||
assert(ptr != NULL);
|
assert(ptr != NULL);
|
||||||
assert(isalloc(tsdn, ptr) == LARGE_MINCLASS);
|
assert(isalloc(tsdn, ptr) == SC_LARGE_MINCLASS);
|
||||||
assert(usize <= SMALL_MAXCLASS);
|
assert(usize <= SC_SMALL_MAXCLASS);
|
||||||
|
|
||||||
|
if (config_opt_safety_checks) {
|
||||||
|
safety_check_set_redzone(ptr, usize, SC_LARGE_MINCLASS);
|
||||||
|
}
|
||||||
|
|
||||||
rtree_ctx_t rtree_ctx_fallback;
|
rtree_ctx_t rtree_ctx_fallback;
|
||||||
rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
|
rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
|
||||||
@ -1434,15 +1582,15 @@ arena_prof_demote(tsdn_t *tsdn, extent_t *extent, const void *ptr) {
|
|||||||
cassert(config_prof);
|
cassert(config_prof);
|
||||||
assert(ptr != NULL);
|
assert(ptr != NULL);
|
||||||
|
|
||||||
extent_szind_set(extent, NBINS);
|
extent_szind_set(extent, SC_NBINS);
|
||||||
rtree_ctx_t rtree_ctx_fallback;
|
rtree_ctx_t rtree_ctx_fallback;
|
||||||
rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
|
rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
|
||||||
rtree_szind_slab_update(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr,
|
rtree_szind_slab_update(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr,
|
||||||
NBINS, false);
|
SC_NBINS, false);
|
||||||
|
|
||||||
assert(isalloc(tsdn, ptr) == LARGE_MINCLASS);
|
assert(isalloc(tsdn, ptr) == SC_LARGE_MINCLASS);
|
||||||
|
|
||||||
return LARGE_MINCLASS;
|
return SC_LARGE_MINCLASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1452,10 +1600,19 @@ arena_dalloc_promoted(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
|
|||||||
assert(opt_prof);
|
assert(opt_prof);
|
||||||
|
|
||||||
extent_t *extent = iealloc(tsdn, ptr);
|
extent_t *extent = iealloc(tsdn, ptr);
|
||||||
size_t usize = arena_prof_demote(tsdn, extent, ptr);
|
size_t usize = extent_usize_get(extent);
|
||||||
if (usize <= tcache_maxclass) {
|
size_t bumped_usize = arena_prof_demote(tsdn, extent, ptr);
|
||||||
|
if (config_opt_safety_checks && usize < SC_LARGE_MINCLASS) {
|
||||||
|
/*
|
||||||
|
* Currently, we only do redzoning for small sampled
|
||||||
|
* allocations.
|
||||||
|
*/
|
||||||
|
assert(bumped_usize == SC_LARGE_MINCLASS);
|
||||||
|
safety_check_verify_redzone(ptr, usize, bumped_usize);
|
||||||
|
}
|
||||||
|
if (bumped_usize <= tcache_maxclass && tcache != NULL) {
|
||||||
tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr,
|
tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr,
|
||||||
sz_size2index(usize), slow_path);
|
sz_size2index(bumped_usize), slow_path);
|
||||||
} else {
|
} else {
|
||||||
large_dalloc(tsdn, extent);
|
large_dalloc(tsdn, extent);
|
||||||
}
|
}
|
||||||
@ -1499,7 +1656,7 @@ arena_dalloc_bin_slab(tsdn_t *tsdn, arena_t *arena, extent_t *slab,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
arena_bin_lower_slab(UNUSED tsdn_t *tsdn, arena_t *arena, extent_t *slab,
|
arena_bin_lower_slab(tsdn_t *tsdn, arena_t *arena, extent_t *slab,
|
||||||
bin_t *bin) {
|
bin_t *bin) {
|
||||||
assert(extent_nfree_get(slab) > 0);
|
assert(extent_nfree_get(slab) > 0);
|
||||||
|
|
||||||
@ -1526,11 +1683,9 @@ arena_bin_lower_slab(UNUSED tsdn_t *tsdn, arena_t *arena, extent_t *slab,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
arena_dalloc_bin_locked_impl(tsdn_t *tsdn, arena_t *arena, extent_t *slab,
|
arena_dalloc_bin_locked_impl(tsdn_t *tsdn, arena_t *arena, bin_t *bin,
|
||||||
void *ptr, bool junked) {
|
szind_t binind, extent_t *slab, void *ptr, bool junked) {
|
||||||
arena_slab_data_t *slab_data = extent_slab_data_get(slab);
|
arena_slab_data_t *slab_data = extent_slab_data_get(slab);
|
||||||
szind_t binind = extent_szind_get(slab);
|
|
||||||
bin_t *bin = &arena->bins[binind];
|
|
||||||
const bin_info_t *bin_info = &bin_infos[binind];
|
const bin_info_t *bin_info = &bin_infos[binind];
|
||||||
|
|
||||||
if (!junked && config_fill && unlikely(opt_junk_free)) {
|
if (!junked && config_fill && unlikely(opt_junk_free)) {
|
||||||
@ -1554,18 +1709,21 @@ arena_dalloc_bin_locked_impl(tsdn_t *tsdn, arena_t *arena, extent_t *slab,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
arena_dalloc_bin_junked_locked(tsdn_t *tsdn, arena_t *arena, extent_t *extent,
|
arena_dalloc_bin_junked_locked(tsdn_t *tsdn, arena_t *arena, bin_t *bin,
|
||||||
void *ptr) {
|
szind_t binind, extent_t *extent, void *ptr) {
|
||||||
arena_dalloc_bin_locked_impl(tsdn, arena, extent, ptr, true);
|
arena_dalloc_bin_locked_impl(tsdn, arena, bin, binind, extent, ptr,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
arena_dalloc_bin(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr) {
|
arena_dalloc_bin(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr) {
|
||||||
szind_t binind = extent_szind_get(extent);
|
szind_t binind = extent_szind_get(extent);
|
||||||
bin_t *bin = &arena->bins[binind];
|
unsigned binshard = extent_binshard_get(extent);
|
||||||
|
bin_t *bin = &arena->bins[binind].bin_shards[binshard];
|
||||||
|
|
||||||
malloc_mutex_lock(tsdn, &bin->lock);
|
malloc_mutex_lock(tsdn, &bin->lock);
|
||||||
arena_dalloc_bin_locked_impl(tsdn, arena, extent, ptr, false);
|
arena_dalloc_bin_locked_impl(tsdn, arena, bin, binind, extent, ptr,
|
||||||
|
false);
|
||||||
malloc_mutex_unlock(tsdn, &bin->lock);
|
malloc_mutex_unlock(tsdn, &bin->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1580,38 +1738,48 @@ arena_dalloc_small(tsdn_t *tsdn, void *ptr) {
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
arena_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
|
arena_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
|
||||||
size_t extra, bool zero) {
|
size_t extra, bool zero, size_t *newsize) {
|
||||||
|
bool ret;
|
||||||
/* Calls with non-zero extra had to clamp extra. */
|
/* Calls with non-zero extra had to clamp extra. */
|
||||||
assert(extra == 0 || size + extra <= LARGE_MAXCLASS);
|
assert(extra == 0 || size + extra <= SC_LARGE_MAXCLASS);
|
||||||
|
|
||||||
if (unlikely(size > LARGE_MAXCLASS)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
extent_t *extent = iealloc(tsdn, ptr);
|
extent_t *extent = iealloc(tsdn, ptr);
|
||||||
|
if (unlikely(size > SC_LARGE_MAXCLASS)) {
|
||||||
|
ret = true;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
size_t usize_min = sz_s2u(size);
|
size_t usize_min = sz_s2u(size);
|
||||||
size_t usize_max = sz_s2u(size + extra);
|
size_t usize_max = sz_s2u(size + extra);
|
||||||
if (likely(oldsize <= SMALL_MAXCLASS && usize_min <= SMALL_MAXCLASS)) {
|
if (likely(oldsize <= SC_SMALL_MAXCLASS && usize_min
|
||||||
|
<= SC_SMALL_MAXCLASS)) {
|
||||||
/*
|
/*
|
||||||
* Avoid moving the allocation if the size class can be left the
|
* Avoid moving the allocation if the size class can be left the
|
||||||
* same.
|
* same.
|
||||||
*/
|
*/
|
||||||
assert(bin_infos[sz_size2index(oldsize)].reg_size ==
|
assert(bin_infos[sz_size2index(oldsize)].reg_size ==
|
||||||
oldsize);
|
oldsize);
|
||||||
if ((usize_max > SMALL_MAXCLASS || sz_size2index(usize_max) !=
|
if ((usize_max > SC_SMALL_MAXCLASS
|
||||||
sz_size2index(oldsize)) && (size > oldsize || usize_max <
|
|| sz_size2index(usize_max) != sz_size2index(oldsize))
|
||||||
oldsize)) {
|
&& (size > oldsize || usize_max < oldsize)) {
|
||||||
return true;
|
ret = true;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
arena_decay_tick(tsdn, extent_arena_get(extent));
|
arena_decay_tick(tsdn, extent_arena_get(extent));
|
||||||
return false;
|
ret = false;
|
||||||
} else if (oldsize >= LARGE_MINCLASS && usize_max >= LARGE_MINCLASS) {
|
} else if (oldsize >= SC_LARGE_MINCLASS
|
||||||
return large_ralloc_no_move(tsdn, extent, usize_min, usize_max,
|
&& usize_max >= SC_LARGE_MINCLASS) {
|
||||||
|
ret = large_ralloc_no_move(tsdn, extent, usize_min, usize_max,
|
||||||
zero);
|
zero);
|
||||||
|
} else {
|
||||||
|
ret = true;
|
||||||
}
|
}
|
||||||
|
done:
|
||||||
|
assert(extent == iealloc(tsdn, ptr));
|
||||||
|
*newsize = extent_usize_get(extent);
|
||||||
|
|
||||||
return true;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
@ -1622,7 +1790,7 @@ arena_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize,
|
|||||||
zero, tcache, true);
|
zero, tcache, true);
|
||||||
}
|
}
|
||||||
usize = sz_sa2u(usize, alignment);
|
usize = sz_sa2u(usize, alignment);
|
||||||
if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) {
|
if (unlikely(usize == 0 || usize > SC_LARGE_MAXCLASS)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return ipalloct(tsdn, usize, alignment, zero, tcache, arena);
|
return ipalloct(tsdn, usize, alignment, zero, tcache, arena);
|
||||||
@ -1630,22 +1798,30 @@ arena_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize,
|
|||||||
|
|
||||||
void *
|
void *
|
||||||
arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize,
|
arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize,
|
||||||
size_t size, size_t alignment, bool zero, tcache_t *tcache) {
|
size_t size, size_t alignment, bool zero, tcache_t *tcache,
|
||||||
|
hook_ralloc_args_t *hook_args) {
|
||||||
size_t usize = sz_s2u(size);
|
size_t usize = sz_s2u(size);
|
||||||
if (unlikely(usize == 0 || size > LARGE_MAXCLASS)) {
|
if (unlikely(usize == 0 || size > SC_LARGE_MAXCLASS)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (likely(usize <= SMALL_MAXCLASS)) {
|
if (likely(usize <= SC_SMALL_MAXCLASS)) {
|
||||||
/* Try to avoid moving the allocation. */
|
/* Try to avoid moving the allocation. */
|
||||||
if (!arena_ralloc_no_move(tsdn, ptr, oldsize, usize, 0, zero)) {
|
UNUSED size_t newsize;
|
||||||
|
if (!arena_ralloc_no_move(tsdn, ptr, oldsize, usize, 0, zero,
|
||||||
|
&newsize)) {
|
||||||
|
hook_invoke_expand(hook_args->is_realloc
|
||||||
|
? hook_expand_realloc : hook_expand_rallocx,
|
||||||
|
ptr, oldsize, usize, (uintptr_t)ptr,
|
||||||
|
hook_args->args);
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldsize >= LARGE_MINCLASS && usize >= LARGE_MINCLASS) {
|
if (oldsize >= SC_LARGE_MINCLASS
|
||||||
return large_ralloc(tsdn, arena, iealloc(tsdn, ptr), usize,
|
&& usize >= SC_LARGE_MINCLASS) {
|
||||||
alignment, zero, tcache);
|
return large_ralloc(tsdn, arena, ptr, usize,
|
||||||
|
alignment, zero, tcache, hook_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1658,11 +1834,16 @@ arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hook_invoke_alloc(hook_args->is_realloc
|
||||||
|
? hook_alloc_realloc : hook_alloc_rallocx, ret, (uintptr_t)ret,
|
||||||
|
hook_args->args);
|
||||||
|
hook_invoke_dalloc(hook_args->is_realloc
|
||||||
|
? hook_dalloc_realloc : hook_dalloc_rallocx, ptr, hook_args->args);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Junk/zero-filling were already done by
|
* Junk/zero-filling were already done by
|
||||||
* ipalloc()/arena_malloc().
|
* ipalloc()/arena_malloc().
|
||||||
*/
|
*/
|
||||||
|
|
||||||
size_t copysize = (usize < oldsize) ? usize : oldsize;
|
size_t copysize = (usize < oldsize) ? usize : oldsize;
|
||||||
memcpy(ret, ptr, copysize);
|
memcpy(ret, ptr, copysize);
|
||||||
isdalloct(tsdn, ptr, oldsize, tcache, NULL, true);
|
isdalloct(tsdn, ptr, oldsize, tcache, NULL, true);
|
||||||
@ -1720,8 +1901,7 @@ arena_retain_grow_limit_get_set(tsd_t *tsd, arena_t *arena, size_t *old_limit,
|
|||||||
if (new_limit != NULL) {
|
if (new_limit != NULL) {
|
||||||
size_t limit = *new_limit;
|
size_t limit = *new_limit;
|
||||||
/* Grow no more than the new limit. */
|
/* Grow no more than the new limit. */
|
||||||
if ((new_ind = sz_psz2ind(limit + 1) - 1) >
|
if ((new_ind = sz_psz2ind(limit + 1) - 1) >= SC_NPSIZES) {
|
||||||
EXTENT_GROW_MAX_PIND) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1773,7 +1953,12 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
arena = (arena_t *)base_alloc(tsdn, base, sizeof(arena_t), CACHELINE);
|
unsigned nbins_total = 0;
|
||||||
|
for (i = 0; i < SC_NBINS; i++) {
|
||||||
|
nbins_total += bin_infos[i].n_shards;
|
||||||
|
}
|
||||||
|
size_t arena_size = sizeof(arena_t) + sizeof(bin_t) * nbins_total;
|
||||||
|
arena = (arena_t *)base_alloc(tsdn, base, arena_size, CACHELINE);
|
||||||
if (arena == NULL) {
|
if (arena == NULL) {
|
||||||
goto label_error;
|
goto label_error;
|
||||||
}
|
}
|
||||||
@ -1865,7 +2050,7 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
arena->extent_grow_next = sz_psz2ind(HUGEPAGE);
|
arena->extent_grow_next = sz_psz2ind(HUGEPAGE);
|
||||||
arena->retain_grow_limit = EXTENT_GROW_MAX_PIND;
|
arena->retain_grow_limit = sz_psz2ind(SC_LARGE_MAXCLASS);
|
||||||
if (malloc_mutex_init(&arena->extent_grow_mtx, "extent_grow",
|
if (malloc_mutex_init(&arena->extent_grow_mtx, "extent_grow",
|
||||||
WITNESS_RANK_EXTENT_GROW, malloc_mutex_rank_exclusive)) {
|
WITNESS_RANK_EXTENT_GROW, malloc_mutex_rank_exclusive)) {
|
||||||
goto label_error;
|
goto label_error;
|
||||||
@ -1878,12 +2063,20 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize bins. */
|
/* Initialize bins. */
|
||||||
for (i = 0; i < NBINS; i++) {
|
uintptr_t bin_addr = (uintptr_t)arena + sizeof(arena_t);
|
||||||
bool err = bin_init(&arena->bins[i]);
|
atomic_store_u(&arena->binshard_next, 0, ATOMIC_RELEASE);
|
||||||
|
for (i = 0; i < SC_NBINS; i++) {
|
||||||
|
unsigned nshards = bin_infos[i].n_shards;
|
||||||
|
arena->bins[i].bin_shards = (bin_t *)bin_addr;
|
||||||
|
bin_addr += nshards * sizeof(bin_t);
|
||||||
|
for (unsigned j = 0; j < nshards; j++) {
|
||||||
|
bool err = bin_init(&arena->bins[i].bin_shards[j]);
|
||||||
if (err) {
|
if (err) {
|
||||||
goto label_error;
|
goto label_error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
assert(bin_addr == (uintptr_t)arena + arena_size);
|
||||||
|
|
||||||
arena->base = base;
|
arena->base = base;
|
||||||
/* Set arena before creating background threads. */
|
/* Set arena before creating background threads. */
|
||||||
@ -1900,8 +2093,8 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) {
|
|||||||
*/
|
*/
|
||||||
assert(!tsdn_null(tsdn));
|
assert(!tsdn_null(tsdn));
|
||||||
pre_reentrancy(tsdn_tsd(tsdn), arena);
|
pre_reentrancy(tsdn_tsd(tsdn), arena);
|
||||||
if (hooks_arena_new_hook) {
|
if (test_hooks_arena_new_hook) {
|
||||||
hooks_arena_new_hook();
|
test_hooks_arena_new_hook();
|
||||||
}
|
}
|
||||||
post_reentrancy(tsdn_tsd(tsdn));
|
post_reentrancy(tsdn_tsd(tsdn));
|
||||||
}
|
}
|
||||||
@ -1914,20 +2107,75 @@ label_error:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
arena_t *
|
||||||
|
arena_choose_huge(tsd_t *tsd) {
|
||||||
|
/* huge_arena_ind can be 0 during init (will use a0). */
|
||||||
|
if (huge_arena_ind == 0) {
|
||||||
|
assert(!malloc_initialized());
|
||||||
|
}
|
||||||
|
|
||||||
|
arena_t *huge_arena = arena_get(tsd_tsdn(tsd), huge_arena_ind, false);
|
||||||
|
if (huge_arena == NULL) {
|
||||||
|
/* Create the huge arena on demand. */
|
||||||
|
assert(huge_arena_ind != 0);
|
||||||
|
huge_arena = arena_get(tsd_tsdn(tsd), huge_arena_ind, true);
|
||||||
|
if (huge_arena == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Purge eagerly for huge allocations, because: 1) number of
|
||||||
|
* huge allocations is usually small, which means ticker based
|
||||||
|
* decay is not reliable; and 2) less immediate reuse is
|
||||||
|
* expected for huge allocations.
|
||||||
|
*/
|
||||||
|
if (arena_dirty_decay_ms_default_get() > 0) {
|
||||||
|
arena_dirty_decay_ms_set(tsd_tsdn(tsd), huge_arena, 0);
|
||||||
|
}
|
||||||
|
if (arena_muzzy_decay_ms_default_get() > 0) {
|
||||||
|
arena_muzzy_decay_ms_set(tsd_tsdn(tsd), huge_arena, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return huge_arena;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
arena_init_huge(void) {
|
||||||
|
bool huge_enabled;
|
||||||
|
|
||||||
|
/* The threshold should be large size class. */
|
||||||
|
if (opt_oversize_threshold > SC_LARGE_MAXCLASS ||
|
||||||
|
opt_oversize_threshold < SC_LARGE_MINCLASS) {
|
||||||
|
opt_oversize_threshold = 0;
|
||||||
|
oversize_threshold = SC_LARGE_MAXCLASS + PAGE;
|
||||||
|
huge_enabled = false;
|
||||||
|
} else {
|
||||||
|
/* Reserve the index for the huge arena. */
|
||||||
|
huge_arena_ind = narenas_total_get();
|
||||||
|
oversize_threshold = opt_oversize_threshold;
|
||||||
|
huge_enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return huge_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
arena_is_huge(unsigned arena_ind) {
|
||||||
|
if (huge_arena_ind == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (arena_ind == huge_arena_ind);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
arena_boot(void) {
|
arena_boot(sc_data_t *sc_data) {
|
||||||
arena_dirty_decay_ms_default_set(opt_dirty_decay_ms);
|
arena_dirty_decay_ms_default_set(opt_dirty_decay_ms);
|
||||||
arena_muzzy_decay_ms_default_set(opt_muzzy_decay_ms);
|
arena_muzzy_decay_ms_default_set(opt_muzzy_decay_ms);
|
||||||
#define REGIND_bin_yes(index, reg_size) \
|
for (unsigned i = 0; i < SC_NBINS; i++) {
|
||||||
div_init(&arena_binind_div_info[(index)], (reg_size));
|
sc_t *sc = &sc_data->sc[i];
|
||||||
#define REGIND_bin_no(index, reg_size)
|
div_init(&arena_binind_div_info[i],
|
||||||
#define SC(index, lg_grp, lg_delta, ndelta, psz, bin, pgs, \
|
(1U << sc->lg_base) + (sc->ndelta << sc->lg_delta));
|
||||||
lg_delta_lookup) \
|
}
|
||||||
REGIND_bin_##bin(index, (1U<<lg_grp) + (ndelta << lg_delta))
|
|
||||||
SIZE_CLASSES
|
|
||||||
#undef REGIND_bin_yes
|
|
||||||
#undef REGIND_bin_no
|
|
||||||
#undef SC
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1972,8 +2220,10 @@ arena_prefork6(tsdn_t *tsdn, arena_t *arena) {
|
|||||||
|
|
||||||
void
|
void
|
||||||
arena_prefork7(tsdn_t *tsdn, arena_t *arena) {
|
arena_prefork7(tsdn_t *tsdn, arena_t *arena) {
|
||||||
for (unsigned i = 0; i < NBINS; i++) {
|
for (unsigned i = 0; i < SC_NBINS; i++) {
|
||||||
bin_prefork(tsdn, &arena->bins[i]);
|
for (unsigned j = 0; j < bin_infos[i].n_shards; j++) {
|
||||||
|
bin_prefork(tsdn, &arena->bins[i].bin_shards[j]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1981,8 +2231,11 @@ void
|
|||||||
arena_postfork_parent(tsdn_t *tsdn, arena_t *arena) {
|
arena_postfork_parent(tsdn_t *tsdn, arena_t *arena) {
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
for (i = 0; i < NBINS; i++) {
|
for (i = 0; i < SC_NBINS; i++) {
|
||||||
bin_postfork_parent(tsdn, &arena->bins[i]);
|
for (unsigned j = 0; j < bin_infos[i].n_shards; j++) {
|
||||||
|
bin_postfork_parent(tsdn,
|
||||||
|
&arena->bins[i].bin_shards[j]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
malloc_mutex_postfork_parent(tsdn, &arena->large_mtx);
|
malloc_mutex_postfork_parent(tsdn, &arena->large_mtx);
|
||||||
base_postfork_parent(tsdn, arena->base);
|
base_postfork_parent(tsdn, arena->base);
|
||||||
@ -2025,8 +2278,10 @@ arena_postfork_child(tsdn_t *tsdn, arena_t *arena) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < NBINS; i++) {
|
for (i = 0; i < SC_NBINS; i++) {
|
||||||
bin_postfork_child(tsdn, &arena->bins[i]);
|
for (unsigned j = 0; j < bin_infos[i].n_shards; j++) {
|
||||||
|
bin_postfork_child(tsdn, &arena->bins[i].bin_shards[j]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
malloc_mutex_postfork_child(tsdn, &arena->large_mtx);
|
malloc_mutex_postfork_child(tsdn, &arena->large_mtx);
|
||||||
base_postfork_child(tsdn, arena->base);
|
base_postfork_child(tsdn, arena->base);
|
||||||
|
58
deps/jemalloc/src/background_thread.c
vendored
58
deps/jemalloc/src/background_thread.c
vendored
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
#include "jemalloc/internal/assert.h"
|
#include "jemalloc/internal/assert.h"
|
||||||
|
|
||||||
|
JEMALLOC_DIAGNOSTIC_DISABLE_SPURIOUS
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* Data. */
|
/* Data. */
|
||||||
|
|
||||||
@ -11,7 +13,7 @@
|
|||||||
#define BACKGROUND_THREAD_DEFAULT false
|
#define BACKGROUND_THREAD_DEFAULT false
|
||||||
/* Read-only after initialization. */
|
/* Read-only after initialization. */
|
||||||
bool opt_background_thread = BACKGROUND_THREAD_DEFAULT;
|
bool opt_background_thread = BACKGROUND_THREAD_DEFAULT;
|
||||||
size_t opt_max_background_threads = MAX_BACKGROUND_THREAD_LIMIT;
|
size_t opt_max_background_threads = MAX_BACKGROUND_THREAD_LIMIT + 1;
|
||||||
|
|
||||||
/* Used for thread creation, termination and stats. */
|
/* Used for thread creation, termination and stats. */
|
||||||
malloc_mutex_t background_thread_lock;
|
malloc_mutex_t background_thread_lock;
|
||||||
@ -22,13 +24,9 @@ size_t max_background_threads;
|
|||||||
/* Thread info per-index. */
|
/* Thread info per-index. */
|
||||||
background_thread_info_t *background_thread_info;
|
background_thread_info_t *background_thread_info;
|
||||||
|
|
||||||
/* False if no necessary runtime support. */
|
|
||||||
bool can_enable_background_thread;
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
#ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER
|
#ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER
|
||||||
#include <dlfcn.h>
|
|
||||||
|
|
||||||
static int (*pthread_create_fptr)(pthread_t *__restrict, const pthread_attr_t *,
|
static int (*pthread_create_fptr)(pthread_t *__restrict, const pthread_attr_t *,
|
||||||
void *(*)(void *), void *__restrict);
|
void *(*)(void *), void *__restrict);
|
||||||
@ -81,7 +79,7 @@ background_thread_info_init(tsdn_t *tsdn, background_thread_info_t *info) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
set_current_thread_affinity(UNUSED int cpu) {
|
set_current_thread_affinity(int cpu) {
|
||||||
#if defined(JEMALLOC_HAVE_SCHED_SETAFFINITY)
|
#if defined(JEMALLOC_HAVE_SCHED_SETAFFINITY)
|
||||||
cpu_set_t cpuset;
|
cpu_set_t cpuset;
|
||||||
CPU_ZERO(&cpuset);
|
CPU_ZERO(&cpuset);
|
||||||
@ -510,6 +508,8 @@ background_thread_entry(void *ind_arg) {
|
|||||||
assert(thread_ind < max_background_threads);
|
assert(thread_ind < max_background_threads);
|
||||||
#ifdef JEMALLOC_HAVE_PTHREAD_SETNAME_NP
|
#ifdef JEMALLOC_HAVE_PTHREAD_SETNAME_NP
|
||||||
pthread_setname_np(pthread_self(), "jemalloc_bg_thd");
|
pthread_setname_np(pthread_self(), "jemalloc_bg_thd");
|
||||||
|
#elif defined(__FreeBSD__)
|
||||||
|
pthread_set_name_np(pthread_self(), "jemalloc_bg_thd");
|
||||||
#endif
|
#endif
|
||||||
if (opt_percpu_arena != percpu_arena_disabled) {
|
if (opt_percpu_arena != percpu_arena_disabled) {
|
||||||
set_current_thread_affinity((int)thread_ind);
|
set_current_thread_affinity((int)thread_ind);
|
||||||
@ -534,9 +534,8 @@ background_thread_init(tsd_t *tsd, background_thread_info_t *info) {
|
|||||||
n_background_threads++;
|
n_background_threads++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a new background thread if needed. */
|
static bool
|
||||||
bool
|
background_thread_create_locked(tsd_t *tsd, unsigned arena_ind) {
|
||||||
background_thread_create(tsd_t *tsd, unsigned arena_ind) {
|
|
||||||
assert(have_background_thread);
|
assert(have_background_thread);
|
||||||
malloc_mutex_assert_owner(tsd_tsdn(tsd), &background_thread_lock);
|
malloc_mutex_assert_owner(tsd_tsdn(tsd), &background_thread_lock);
|
||||||
|
|
||||||
@ -589,6 +588,19 @@ background_thread_create(tsd_t *tsd, unsigned arena_ind) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Create a new background thread if needed. */
|
||||||
|
bool
|
||||||
|
background_thread_create(tsd_t *tsd, unsigned arena_ind) {
|
||||||
|
assert(have_background_thread);
|
||||||
|
|
||||||
|
bool ret;
|
||||||
|
malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_lock);
|
||||||
|
ret = background_thread_create_locked(tsd, arena_ind);
|
||||||
|
malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
background_threads_enable(tsd_t *tsd) {
|
background_threads_enable(tsd_t *tsd) {
|
||||||
assert(n_background_threads == 0);
|
assert(n_background_threads == 0);
|
||||||
@ -622,7 +634,7 @@ background_threads_enable(tsd_t *tsd) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return background_thread_create(tsd, 0);
|
return background_thread_create_locked(tsd, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -813,21 +825,34 @@ background_thread_stats_read(tsdn_t *tsdn, background_thread_stats_t *stats) {
|
|||||||
#undef BILLION
|
#undef BILLION
|
||||||
#undef BACKGROUND_THREAD_MIN_INTERVAL_NS
|
#undef BACKGROUND_THREAD_MIN_INTERVAL_NS
|
||||||
|
|
||||||
|
#ifdef JEMALLOC_HAVE_DLSYM
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
pthread_create_fptr_init(void) {
|
pthread_create_fptr_init(void) {
|
||||||
if (pthread_create_fptr != NULL) {
|
if (pthread_create_fptr != NULL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* Try the next symbol first, because 1) when use lazy_lock we have a
|
||||||
|
* wrapper for pthread_create; and 2) application may define its own
|
||||||
|
* wrapper as well (and can call malloc within the wrapper).
|
||||||
|
*/
|
||||||
|
#ifdef JEMALLOC_HAVE_DLSYM
|
||||||
pthread_create_fptr = dlsym(RTLD_NEXT, "pthread_create");
|
pthread_create_fptr = dlsym(RTLD_NEXT, "pthread_create");
|
||||||
|
#else
|
||||||
|
pthread_create_fptr = NULL;
|
||||||
|
#endif
|
||||||
if (pthread_create_fptr == NULL) {
|
if (pthread_create_fptr == NULL) {
|
||||||
can_enable_background_thread = false;
|
if (config_lazy_lock) {
|
||||||
if (config_lazy_lock || opt_background_thread) {
|
|
||||||
malloc_write("<jemalloc>: Error in dlsym(RTLD_NEXT, "
|
malloc_write("<jemalloc>: Error in dlsym(RTLD_NEXT, "
|
||||||
"\"pthread_create\")\n");
|
"\"pthread_create\")\n");
|
||||||
abort();
|
abort();
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
can_enable_background_thread = true;
|
/* Fall back to the default symbol. */
|
||||||
|
pthread_create_fptr = pthread_create;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -872,9 +897,8 @@ background_thread_boot1(tsdn_t *tsdn) {
|
|||||||
assert(have_background_thread);
|
assert(have_background_thread);
|
||||||
assert(narenas_total_get() > 0);
|
assert(narenas_total_get() > 0);
|
||||||
|
|
||||||
if (opt_max_background_threads == MAX_BACKGROUND_THREAD_LIMIT &&
|
if (opt_max_background_threads > MAX_BACKGROUND_THREAD_LIMIT) {
|
||||||
ncpus < MAX_BACKGROUND_THREAD_LIMIT) {
|
opt_max_background_threads = DEFAULT_NUM_BACKGROUND_THREAD;
|
||||||
opt_max_background_threads = ncpus;
|
|
||||||
}
|
}
|
||||||
max_background_threads = opt_max_background_threads;
|
max_background_threads = opt_max_background_threads;
|
||||||
|
|
||||||
|
8
deps/jemalloc/src/base.c
vendored
8
deps/jemalloc/src/base.c
vendored
@ -262,8 +262,8 @@ base_block_alloc(tsdn_t *tsdn, base_t *base, extent_hooks_t *extent_hooks,
|
|||||||
*/
|
*/
|
||||||
size_t min_block_size = HUGEPAGE_CEILING(sz_psz2u(header_size + gap_size
|
size_t min_block_size = HUGEPAGE_CEILING(sz_psz2u(header_size + gap_size
|
||||||
+ usize));
|
+ usize));
|
||||||
pszind_t pind_next = (*pind_last + 1 < NPSIZES) ? *pind_last + 1 :
|
pszind_t pind_next = (*pind_last + 1 < sz_psz2ind(SC_LARGE_MAXCLASS)) ?
|
||||||
*pind_last;
|
*pind_last + 1 : *pind_last;
|
||||||
size_t next_block_size = HUGEPAGE_CEILING(sz_pind2sz(pind_next));
|
size_t next_block_size = HUGEPAGE_CEILING(sz_pind2sz(pind_next));
|
||||||
size_t block_size = (min_block_size > next_block_size) ? min_block_size
|
size_t block_size = (min_block_size > next_block_size) ? min_block_size
|
||||||
: next_block_size;
|
: next_block_size;
|
||||||
@ -372,7 +372,7 @@ base_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) {
|
|||||||
base->extent_sn_next = extent_sn_next;
|
base->extent_sn_next = extent_sn_next;
|
||||||
base->blocks = block;
|
base->blocks = block;
|
||||||
base->auto_thp_switched = false;
|
base->auto_thp_switched = false;
|
||||||
for (szind_t i = 0; i < NSIZES; i++) {
|
for (szind_t i = 0; i < SC_NSIZES; i++) {
|
||||||
extent_heap_new(&base->avail[i]);
|
extent_heap_new(&base->avail[i]);
|
||||||
}
|
}
|
||||||
if (config_stats) {
|
if (config_stats) {
|
||||||
@ -426,7 +426,7 @@ base_alloc_impl(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment,
|
|||||||
|
|
||||||
extent_t *extent = NULL;
|
extent_t *extent = NULL;
|
||||||
malloc_mutex_lock(tsdn, &base->mtx);
|
malloc_mutex_lock(tsdn, &base->mtx);
|
||||||
for (szind_t i = sz_size2index(asize); i < NSIZES; i++) {
|
for (szind_t i = sz_size2index(asize); i < SC_NSIZES; i++) {
|
||||||
extent = extent_heap_remove_first(&base->avail[i]);
|
extent = extent_heap_remove_first(&base->avail[i]);
|
||||||
if (extent != NULL) {
|
if (extent != NULL) {
|
||||||
/* Use existing space. */
|
/* Use existing space. */
|
||||||
|
73
deps/jemalloc/src/bin.c
vendored
73
deps/jemalloc/src/bin.c
vendored
@ -1,23 +1,68 @@
|
|||||||
#include "jemalloc/internal/jemalloc_preamble.h"
|
#include "jemalloc/internal/jemalloc_preamble.h"
|
||||||
#include "jemalloc/internal/jemalloc_internal_includes.h"
|
#include "jemalloc/internal/jemalloc_internal_includes.h"
|
||||||
|
|
||||||
|
#include "jemalloc/internal/assert.h"
|
||||||
#include "jemalloc/internal/bin.h"
|
#include "jemalloc/internal/bin.h"
|
||||||
|
#include "jemalloc/internal/sc.h"
|
||||||
#include "jemalloc/internal/witness.h"
|
#include "jemalloc/internal/witness.h"
|
||||||
|
|
||||||
const bin_info_t bin_infos[NBINS] = {
|
bin_info_t bin_infos[SC_NBINS];
|
||||||
#define BIN_INFO_bin_yes(reg_size, slab_size, nregs) \
|
|
||||||
{reg_size, slab_size, nregs, BITMAP_INFO_INITIALIZER(nregs)},
|
static void
|
||||||
#define BIN_INFO_bin_no(reg_size, slab_size, nregs)
|
bin_infos_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS],
|
||||||
#define SC(index, lg_grp, lg_delta, ndelta, psz, bin, pgs, \
|
bin_info_t bin_infos[SC_NBINS]) {
|
||||||
lg_delta_lookup) \
|
for (unsigned i = 0; i < SC_NBINS; i++) {
|
||||||
BIN_INFO_bin_##bin((1U<<lg_grp) + (ndelta<<lg_delta), \
|
bin_info_t *bin_info = &bin_infos[i];
|
||||||
(pgs << LG_PAGE), (pgs << LG_PAGE) / ((1U<<lg_grp) + \
|
sc_t *sc = &sc_data->sc[i];
|
||||||
(ndelta<<lg_delta)))
|
bin_info->reg_size = ((size_t)1U << sc->lg_base)
|
||||||
SIZE_CLASSES
|
+ ((size_t)sc->ndelta << sc->lg_delta);
|
||||||
#undef BIN_INFO_bin_yes
|
bin_info->slab_size = (sc->pgs << LG_PAGE);
|
||||||
#undef BIN_INFO_bin_no
|
bin_info->nregs =
|
||||||
#undef SC
|
(uint32_t)(bin_info->slab_size / bin_info->reg_size);
|
||||||
};
|
bin_info->n_shards = bin_shard_sizes[i];
|
||||||
|
bitmap_info_t bitmap_info = BITMAP_INFO_INITIALIZER(
|
||||||
|
bin_info->nregs);
|
||||||
|
bin_info->bitmap_info = bitmap_info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
bin_update_shard_size(unsigned bin_shard_sizes[SC_NBINS], size_t start_size,
|
||||||
|
size_t end_size, size_t nshards) {
|
||||||
|
if (nshards > BIN_SHARDS_MAX || nshards == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start_size > SC_SMALL_MAXCLASS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (end_size > SC_SMALL_MAXCLASS) {
|
||||||
|
end_size = SC_SMALL_MAXCLASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute the index since this may happen before sz init. */
|
||||||
|
szind_t ind1 = sz_size2index_compute(start_size);
|
||||||
|
szind_t ind2 = sz_size2index_compute(end_size);
|
||||||
|
for (unsigned i = ind1; i <= ind2; i++) {
|
||||||
|
bin_shard_sizes[i] = (unsigned)nshards;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
bin_shard_sizes_boot(unsigned bin_shard_sizes[SC_NBINS]) {
|
||||||
|
/* Load the default number of shards. */
|
||||||
|
for (unsigned i = 0; i < SC_NBINS; i++) {
|
||||||
|
bin_shard_sizes[i] = N_BIN_SHARDS_DEFAULT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
bin_boot(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
|
||||||
|
assert(sc_data->initialized);
|
||||||
|
bin_infos_init(sc_data, bin_shard_sizes, bin_infos);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
bin_init(bin_t *bin) {
|
bin_init(bin_t *bin) {
|
||||||
|
7
deps/jemalloc/src/ckh.c
vendored
7
deps/jemalloc/src/ckh.c
vendored
@ -275,7 +275,8 @@ ckh_grow(tsd_t *tsd, ckh_t *ckh) {
|
|||||||
|
|
||||||
lg_curcells++;
|
lg_curcells++;
|
||||||
usize = sz_sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE);
|
usize = sz_sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE);
|
||||||
if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) {
|
if (unlikely(usize == 0
|
||||||
|
|| usize > SC_LARGE_MAXCLASS)) {
|
||||||
ret = true;
|
ret = true;
|
||||||
goto label_return;
|
goto label_return;
|
||||||
}
|
}
|
||||||
@ -320,7 +321,7 @@ ckh_shrink(tsd_t *tsd, ckh_t *ckh) {
|
|||||||
lg_prevbuckets = ckh->lg_curbuckets;
|
lg_prevbuckets = ckh->lg_curbuckets;
|
||||||
lg_curcells = ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS - 1;
|
lg_curcells = ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS - 1;
|
||||||
usize = sz_sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE);
|
usize = sz_sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE);
|
||||||
if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) {
|
if (unlikely(usize == 0 || usize > SC_LARGE_MAXCLASS)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tab = (ckhc_t *)ipallocztm(tsd_tsdn(tsd), usize, CACHELINE, true, NULL,
|
tab = (ckhc_t *)ipallocztm(tsd_tsdn(tsd), usize, CACHELINE, true, NULL,
|
||||||
@ -396,7 +397,7 @@ ckh_new(tsd_t *tsd, ckh_t *ckh, size_t minitems, ckh_hash_t *hash,
|
|||||||
ckh->keycomp = keycomp;
|
ckh->keycomp = keycomp;
|
||||||
|
|
||||||
usize = sz_sa2u(sizeof(ckhc_t) << lg_mincells, CACHELINE);
|
usize = sz_sa2u(sizeof(ckhc_t) << lg_mincells, CACHELINE);
|
||||||
if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) {
|
if (unlikely(usize == 0 || usize > SC_LARGE_MAXCLASS)) {
|
||||||
ret = true;
|
ret = true;
|
||||||
goto label_return;
|
goto label_return;
|
||||||
}
|
}
|
||||||
|
768
deps/jemalloc/src/ctl.c
vendored
768
deps/jemalloc/src/ctl.c
vendored
File diff suppressed because it is too large
Load Diff
438
deps/jemalloc/src/extent.c
vendored
438
deps/jemalloc/src/extent.c
vendored
@ -20,7 +20,7 @@ mutex_pool_t extent_mutex_pool;
|
|||||||
size_t opt_lg_extent_max_active_fit = LG_EXTENT_MAX_ACTIVE_FIT_DEFAULT;
|
size_t opt_lg_extent_max_active_fit = LG_EXTENT_MAX_ACTIVE_FIT_DEFAULT;
|
||||||
|
|
||||||
static const bitmap_info_t extents_bitmap_info =
|
static const bitmap_info_t extents_bitmap_info =
|
||||||
BITMAP_INFO_INITIALIZER(NPSIZES+1);
|
BITMAP_INFO_INITIALIZER(SC_NPSIZES+1);
|
||||||
|
|
||||||
static void *extent_alloc_default(extent_hooks_t *extent_hooks, void *new_addr,
|
static void *extent_alloc_default(extent_hooks_t *extent_hooks, void *new_addr,
|
||||||
size_t size, size_t alignment, bool *zero, bool *commit,
|
size_t size, size_t alignment, bool *zero, bool *commit,
|
||||||
@ -50,20 +50,16 @@ static bool extent_purge_forced_default(extent_hooks_t *extent_hooks,
|
|||||||
static bool extent_purge_forced_impl(tsdn_t *tsdn, arena_t *arena,
|
static bool extent_purge_forced_impl(tsdn_t *tsdn, arena_t *arena,
|
||||||
extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset,
|
extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset,
|
||||||
size_t length, bool growing_retained);
|
size_t length, bool growing_retained);
|
||||||
#ifdef JEMALLOC_MAPS_COALESCE
|
|
||||||
static bool extent_split_default(extent_hooks_t *extent_hooks, void *addr,
|
static bool extent_split_default(extent_hooks_t *extent_hooks, void *addr,
|
||||||
size_t size, size_t size_a, size_t size_b, bool committed,
|
size_t size, size_t size_a, size_t size_b, bool committed,
|
||||||
unsigned arena_ind);
|
unsigned arena_ind);
|
||||||
#endif
|
|
||||||
static extent_t *extent_split_impl(tsdn_t *tsdn, arena_t *arena,
|
static extent_t *extent_split_impl(tsdn_t *tsdn, arena_t *arena,
|
||||||
extent_hooks_t **r_extent_hooks, extent_t *extent, size_t size_a,
|
extent_hooks_t **r_extent_hooks, extent_t *extent, size_t size_a,
|
||||||
szind_t szind_a, bool slab_a, size_t size_b, szind_t szind_b, bool slab_b,
|
szind_t szind_a, bool slab_a, size_t size_b, szind_t szind_b, bool slab_b,
|
||||||
bool growing_retained);
|
bool growing_retained);
|
||||||
#ifdef JEMALLOC_MAPS_COALESCE
|
|
||||||
static bool extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a,
|
static bool extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a,
|
||||||
size_t size_a, void *addr_b, size_t size_b, bool committed,
|
size_t size_a, void *addr_b, size_t size_b, bool committed,
|
||||||
unsigned arena_ind);
|
unsigned arena_ind);
|
||||||
#endif
|
|
||||||
static bool extent_merge_impl(tsdn_t *tsdn, arena_t *arena,
|
static bool extent_merge_impl(tsdn_t *tsdn, arena_t *arena,
|
||||||
extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b,
|
extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b,
|
||||||
bool growing_retained);
|
bool growing_retained);
|
||||||
@ -88,11 +84,9 @@ const extent_hooks_t extent_hooks_default = {
|
|||||||
,
|
,
|
||||||
NULL
|
NULL
|
||||||
#endif
|
#endif
|
||||||
#ifdef JEMALLOC_MAPS_COALESCE
|
|
||||||
,
|
,
|
||||||
extent_split_default,
|
extent_split_default,
|
||||||
extent_merge_default
|
extent_merge_default
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Used exclusively for gdump triggering. */
|
/* Used exclusively for gdump triggering. */
|
||||||
@ -119,9 +113,13 @@ static void extent_record(tsdn_t *tsdn, arena_t *arena,
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
ph_gen(UNUSED, extent_avail_, extent_tree_t, extent_t, ph_link,
|
#define ATTR_NONE /* does nothing */
|
||||||
|
|
||||||
|
ph_gen(ATTR_NONE, extent_avail_, extent_tree_t, extent_t, ph_link,
|
||||||
extent_esnead_comp)
|
extent_esnead_comp)
|
||||||
|
|
||||||
|
#undef ATTR_NONE
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
lock_result_success,
|
lock_result_success,
|
||||||
lock_result_failure,
|
lock_result_failure,
|
||||||
@ -130,13 +128,16 @@ typedef enum {
|
|||||||
|
|
||||||
static lock_result_t
|
static lock_result_t
|
||||||
extent_rtree_leaf_elm_try_lock(tsdn_t *tsdn, rtree_leaf_elm_t *elm,
|
extent_rtree_leaf_elm_try_lock(tsdn_t *tsdn, rtree_leaf_elm_t *elm,
|
||||||
extent_t **result) {
|
extent_t **result, bool inactive_only) {
|
||||||
extent_t *extent1 = rtree_leaf_elm_extent_read(tsdn, &extents_rtree,
|
extent_t *extent1 = rtree_leaf_elm_extent_read(tsdn, &extents_rtree,
|
||||||
elm, true);
|
elm, true);
|
||||||
|
|
||||||
if (extent1 == NULL) {
|
/* Slab implies active extents and should be skipped. */
|
||||||
|
if (extent1 == NULL || (inactive_only && rtree_leaf_elm_slab_read(tsdn,
|
||||||
|
&extents_rtree, elm, true))) {
|
||||||
return lock_result_no_extent;
|
return lock_result_no_extent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It's possible that the extent changed out from under us, and with it
|
* It's possible that the extent changed out from under us, and with it
|
||||||
* the leaf->extent mapping. We have to recheck while holding the lock.
|
* the leaf->extent mapping. We have to recheck while holding the lock.
|
||||||
@ -159,7 +160,8 @@ extent_rtree_leaf_elm_try_lock(tsdn_t *tsdn, rtree_leaf_elm_t *elm,
|
|||||||
* address, and NULL otherwise.
|
* address, and NULL otherwise.
|
||||||
*/
|
*/
|
||||||
static extent_t *
|
static extent_t *
|
||||||
extent_lock_from_addr(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, void *addr) {
|
extent_lock_from_addr(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, void *addr,
|
||||||
|
bool inactive_only) {
|
||||||
extent_t *ret = NULL;
|
extent_t *ret = NULL;
|
||||||
rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, &extents_rtree,
|
rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, &extents_rtree,
|
||||||
rtree_ctx, (uintptr_t)addr, false, false);
|
rtree_ctx, (uintptr_t)addr, false, false);
|
||||||
@ -168,7 +170,8 @@ extent_lock_from_addr(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, void *addr) {
|
|||||||
}
|
}
|
||||||
lock_result_t lock_result;
|
lock_result_t lock_result;
|
||||||
do {
|
do {
|
||||||
lock_result = extent_rtree_leaf_elm_try_lock(tsdn, elm, &ret);
|
lock_result = extent_rtree_leaf_elm_try_lock(tsdn, elm, &ret,
|
||||||
|
inactive_only);
|
||||||
} while (lock_result == lock_result_failure);
|
} while (lock_result == lock_result_failure);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -182,6 +185,7 @@ extent_alloc(tsdn_t *tsdn, arena_t *arena) {
|
|||||||
return base_alloc_extent(tsdn, arena->base);
|
return base_alloc_extent(tsdn, arena->base);
|
||||||
}
|
}
|
||||||
extent_avail_remove(&arena->extent_avail, extent);
|
extent_avail_remove(&arena->extent_avail, extent);
|
||||||
|
atomic_fetch_sub_zu(&arena->extent_avail_cnt, 1, ATOMIC_RELAXED);
|
||||||
malloc_mutex_unlock(tsdn, &arena->extent_avail_mtx);
|
malloc_mutex_unlock(tsdn, &arena->extent_avail_mtx);
|
||||||
return extent;
|
return extent;
|
||||||
}
|
}
|
||||||
@ -190,6 +194,7 @@ void
|
|||||||
extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent) {
|
extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent) {
|
||||||
malloc_mutex_lock(tsdn, &arena->extent_avail_mtx);
|
malloc_mutex_lock(tsdn, &arena->extent_avail_mtx);
|
||||||
extent_avail_insert(&arena->extent_avail, extent);
|
extent_avail_insert(&arena->extent_avail, extent);
|
||||||
|
atomic_fetch_add_zu(&arena->extent_avail_cnt, 1, ATOMIC_RELAXED);
|
||||||
malloc_mutex_unlock(tsdn, &arena->extent_avail_mtx);
|
malloc_mutex_unlock(tsdn, &arena->extent_avail_mtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,7 +260,7 @@ extent_size_quantize_ceil(size_t size) {
|
|||||||
size_t ret;
|
size_t ret;
|
||||||
|
|
||||||
assert(size > 0);
|
assert(size > 0);
|
||||||
assert(size - sz_large_pad <= LARGE_MAXCLASS);
|
assert(size - sz_large_pad <= SC_LARGE_MAXCLASS);
|
||||||
assert((size & PAGE_MASK) == 0);
|
assert((size & PAGE_MASK) == 0);
|
||||||
|
|
||||||
ret = extent_size_quantize_floor(size);
|
ret = extent_size_quantize_floor(size);
|
||||||
@ -284,7 +289,7 @@ extents_init(tsdn_t *tsdn, extents_t *extents, extent_state_t state,
|
|||||||
malloc_mutex_rank_exclusive)) {
|
malloc_mutex_rank_exclusive)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
for (unsigned i = 0; i < NPSIZES+1; i++) {
|
for (unsigned i = 0; i < SC_NPSIZES + 1; i++) {
|
||||||
extent_heap_new(&extents->heaps[i]);
|
extent_heap_new(&extents->heaps[i]);
|
||||||
}
|
}
|
||||||
bitmap_init(extents->bitmap, &extents_bitmap_info, true);
|
bitmap_init(extents->bitmap, &extents_bitmap_info, true);
|
||||||
@ -305,6 +310,32 @@ extents_npages_get(extents_t *extents) {
|
|||||||
return atomic_load_zu(&extents->npages, ATOMIC_RELAXED);
|
return atomic_load_zu(&extents->npages, ATOMIC_RELAXED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
extents_nextents_get(extents_t *extents, pszind_t pind) {
|
||||||
|
return atomic_load_zu(&extents->nextents[pind], ATOMIC_RELAXED);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
extents_nbytes_get(extents_t *extents, pszind_t pind) {
|
||||||
|
return atomic_load_zu(&extents->nbytes[pind], ATOMIC_RELAXED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
extents_stats_add(extents_t *extent, pszind_t pind, size_t sz) {
|
||||||
|
size_t cur = atomic_load_zu(&extent->nextents[pind], ATOMIC_RELAXED);
|
||||||
|
atomic_store_zu(&extent->nextents[pind], cur + 1, ATOMIC_RELAXED);
|
||||||
|
cur = atomic_load_zu(&extent->nbytes[pind], ATOMIC_RELAXED);
|
||||||
|
atomic_store_zu(&extent->nbytes[pind], cur + sz, ATOMIC_RELAXED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
extents_stats_sub(extents_t *extent, pszind_t pind, size_t sz) {
|
||||||
|
size_t cur = atomic_load_zu(&extent->nextents[pind], ATOMIC_RELAXED);
|
||||||
|
atomic_store_zu(&extent->nextents[pind], cur - 1, ATOMIC_RELAXED);
|
||||||
|
cur = atomic_load_zu(&extent->nbytes[pind], ATOMIC_RELAXED);
|
||||||
|
atomic_store_zu(&extent->nbytes[pind], cur - sz, ATOMIC_RELAXED);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
extents_insert_locked(tsdn_t *tsdn, extents_t *extents, extent_t *extent) {
|
extents_insert_locked(tsdn_t *tsdn, extents_t *extents, extent_t *extent) {
|
||||||
malloc_mutex_assert_owner(tsdn, &extents->mtx);
|
malloc_mutex_assert_owner(tsdn, &extents->mtx);
|
||||||
@ -318,6 +349,11 @@ extents_insert_locked(tsdn_t *tsdn, extents_t *extents, extent_t *extent) {
|
|||||||
(size_t)pind);
|
(size_t)pind);
|
||||||
}
|
}
|
||||||
extent_heap_insert(&extents->heaps[pind], extent);
|
extent_heap_insert(&extents->heaps[pind], extent);
|
||||||
|
|
||||||
|
if (config_stats) {
|
||||||
|
extents_stats_add(extents, pind, size);
|
||||||
|
}
|
||||||
|
|
||||||
extent_list_append(&extents->lru, extent);
|
extent_list_append(&extents->lru, extent);
|
||||||
size_t npages = size >> LG_PAGE;
|
size_t npages = size >> LG_PAGE;
|
||||||
/*
|
/*
|
||||||
@ -340,6 +376,11 @@ extents_remove_locked(tsdn_t *tsdn, extents_t *extents, extent_t *extent) {
|
|||||||
size_t psz = extent_size_quantize_floor(size);
|
size_t psz = extent_size_quantize_floor(size);
|
||||||
pszind_t pind = sz_psz2ind(psz);
|
pszind_t pind = sz_psz2ind(psz);
|
||||||
extent_heap_remove(&extents->heaps[pind], extent);
|
extent_heap_remove(&extents->heaps[pind], extent);
|
||||||
|
|
||||||
|
if (config_stats) {
|
||||||
|
extents_stats_sub(extents, pind, size);
|
||||||
|
}
|
||||||
|
|
||||||
if (extent_heap_empty(&extents->heaps[pind])) {
|
if (extent_heap_empty(&extents->heaps[pind])) {
|
||||||
bitmap_set(extents->bitmap, &extents_bitmap_info,
|
bitmap_set(extents->bitmap, &extents_bitmap_info,
|
||||||
(size_t)pind);
|
(size_t)pind);
|
||||||
@ -371,7 +412,7 @@ extents_fit_alignment(extents_t *extents, size_t min_size, size_t max_size,
|
|||||||
&extents_bitmap_info, (size_t)pind); i < pind_max; i =
|
&extents_bitmap_info, (size_t)pind); i < pind_max; i =
|
||||||
(pszind_t)bitmap_ffu(extents->bitmap, &extents_bitmap_info,
|
(pszind_t)bitmap_ffu(extents->bitmap, &extents_bitmap_info,
|
||||||
(size_t)i+1)) {
|
(size_t)i+1)) {
|
||||||
assert(i < NPSIZES);
|
assert(i < SC_NPSIZES);
|
||||||
assert(!extent_heap_empty(&extents->heaps[i]));
|
assert(!extent_heap_empty(&extents->heaps[i]));
|
||||||
extent_t *extent = extent_heap_first(&extents->heaps[i]);
|
extent_t *extent = extent_heap_first(&extents->heaps[i]);
|
||||||
uintptr_t base = (uintptr_t)extent_base_get(extent);
|
uintptr_t base = (uintptr_t)extent_base_get(extent);
|
||||||
@ -394,30 +435,6 @@ extents_fit_alignment(extents_t *extents, size_t min_size, size_t max_size,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do any-best-fit extent selection, i.e. select any extent that best fits. */
|
|
||||||
static extent_t *
|
|
||||||
extents_best_fit_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents,
|
|
||||||
size_t size) {
|
|
||||||
pszind_t pind = sz_psz2ind(extent_size_quantize_ceil(size));
|
|
||||||
pszind_t i = (pszind_t)bitmap_ffu(extents->bitmap, &extents_bitmap_info,
|
|
||||||
(size_t)pind);
|
|
||||||
if (i < NPSIZES+1) {
|
|
||||||
/*
|
|
||||||
* In order to reduce fragmentation, avoid reusing and splitting
|
|
||||||
* large extents for much smaller sizes.
|
|
||||||
*/
|
|
||||||
if ((sz_pind2sz(i) >> opt_lg_extent_max_active_fit) > size) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
assert(!extent_heap_empty(&extents->heaps[i]));
|
|
||||||
extent_t *extent = extent_heap_first(&extents->heaps[i]);
|
|
||||||
assert(extent_size_get(extent) >= size);
|
|
||||||
return extent;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do first-fit extent selection, i.e. select the oldest/lowest extent that is
|
* Do first-fit extent selection, i.e. select the oldest/lowest extent that is
|
||||||
* large enough.
|
* large enough.
|
||||||
@ -428,30 +445,49 @@ extents_first_fit_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents,
|
|||||||
extent_t *ret = NULL;
|
extent_t *ret = NULL;
|
||||||
|
|
||||||
pszind_t pind = sz_psz2ind(extent_size_quantize_ceil(size));
|
pszind_t pind = sz_psz2ind(extent_size_quantize_ceil(size));
|
||||||
|
|
||||||
|
if (!maps_coalesce && !opt_retain) {
|
||||||
|
/*
|
||||||
|
* No split / merge allowed (Windows w/o retain). Try exact fit
|
||||||
|
* only.
|
||||||
|
*/
|
||||||
|
return extent_heap_empty(&extents->heaps[pind]) ? NULL :
|
||||||
|
extent_heap_first(&extents->heaps[pind]);
|
||||||
|
}
|
||||||
|
|
||||||
for (pszind_t i = (pszind_t)bitmap_ffu(extents->bitmap,
|
for (pszind_t i = (pszind_t)bitmap_ffu(extents->bitmap,
|
||||||
&extents_bitmap_info, (size_t)pind); i < NPSIZES+1; i =
|
&extents_bitmap_info, (size_t)pind);
|
||||||
(pszind_t)bitmap_ffu(extents->bitmap, &extents_bitmap_info,
|
i < SC_NPSIZES + 1;
|
||||||
|
i = (pszind_t)bitmap_ffu(extents->bitmap, &extents_bitmap_info,
|
||||||
(size_t)i+1)) {
|
(size_t)i+1)) {
|
||||||
assert(!extent_heap_empty(&extents->heaps[i]));
|
assert(!extent_heap_empty(&extents->heaps[i]));
|
||||||
extent_t *extent = extent_heap_first(&extents->heaps[i]);
|
extent_t *extent = extent_heap_first(&extents->heaps[i]);
|
||||||
assert(extent_size_get(extent) >= size);
|
assert(extent_size_get(extent) >= size);
|
||||||
|
/*
|
||||||
|
* In order to reduce fragmentation, avoid reusing and splitting
|
||||||
|
* large extents for much smaller sizes.
|
||||||
|
*
|
||||||
|
* Only do check for dirty extents (delay_coalesce).
|
||||||
|
*/
|
||||||
|
if (extents->delay_coalesce &&
|
||||||
|
(sz_pind2sz(i) >> opt_lg_extent_max_active_fit) > size) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (ret == NULL || extent_snad_comp(extent, ret) < 0) {
|
if (ret == NULL || extent_snad_comp(extent, ret) < 0) {
|
||||||
ret = extent;
|
ret = extent;
|
||||||
}
|
}
|
||||||
if (i == NPSIZES) {
|
if (i == SC_NPSIZES) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
assert(i < NPSIZES);
|
assert(i < SC_NPSIZES);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do {best,first}-fit extent selection, where the selection policy choice is
|
* Do first-fit extent selection, where the selection policy choice is
|
||||||
* based on extents->delay_coalesce. Best-fit selection requires less
|
* based on extents->delay_coalesce.
|
||||||
* searching, but its layout policy is less stable and may cause higher virtual
|
|
||||||
* memory fragmentation as a side effect.
|
|
||||||
*/
|
*/
|
||||||
static extent_t *
|
static extent_t *
|
||||||
extents_fit_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents,
|
extents_fit_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents,
|
||||||
@ -464,8 +500,7 @@ extents_fit_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
extent_t *extent = extents->delay_coalesce ?
|
extent_t *extent =
|
||||||
extents_best_fit_locked(tsdn, arena, extents, max_size) :
|
|
||||||
extents_first_fit_locked(tsdn, arena, extents, max_size);
|
extents_first_fit_locked(tsdn, arena, extents, max_size);
|
||||||
|
|
||||||
if (alignment > PAGE && extent == NULL) {
|
if (alignment > PAGE && extent == NULL) {
|
||||||
@ -592,16 +627,24 @@ label_return:
|
|||||||
return extent;
|
return extent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This can only happen when we fail to allocate a new extent struct (which
|
||||||
|
* indicates OOM), e.g. when trying to split an existing extent.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
extents_leak(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks,
|
extents_abandon_vm(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks,
|
||||||
extents_t *extents, extent_t *extent, bool growing_retained) {
|
extents_t *extents, extent_t *extent, bool growing_retained) {
|
||||||
|
size_t sz = extent_size_get(extent);
|
||||||
|
if (config_stats) {
|
||||||
|
arena_stats_accum_zu(&arena->stats.abandoned_vm, sz);
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Leak extent after making sure its pages have already been purged, so
|
* Leak extent after making sure its pages have already been purged, so
|
||||||
* that this is only a virtual memory leak.
|
* that this is only a virtual memory leak.
|
||||||
*/
|
*/
|
||||||
if (extents_state_get(extents) == extent_state_dirty) {
|
if (extents_state_get(extents) == extent_state_dirty) {
|
||||||
if (extent_purge_lazy_impl(tsdn, arena, r_extent_hooks,
|
if (extent_purge_lazy_impl(tsdn, arena, r_extent_hooks,
|
||||||
extent, 0, extent_size_get(extent), growing_retained)) {
|
extent, 0, sz, growing_retained)) {
|
||||||
extent_purge_forced_impl(tsdn, arena, r_extent_hooks,
|
extent_purge_forced_impl(tsdn, arena, r_extent_hooks,
|
||||||
extent, 0, extent_size_get(extent),
|
extent, 0, extent_size_get(extent),
|
||||||
growing_retained);
|
growing_retained);
|
||||||
@ -748,6 +791,7 @@ extent_register_impl(tsdn_t *tsdn, extent_t *extent, bool gdump_add) {
|
|||||||
|
|
||||||
if (extent_rtree_leaf_elms_lookup(tsdn, rtree_ctx, extent, false, true,
|
if (extent_rtree_leaf_elms_lookup(tsdn, rtree_ctx, extent, false, true,
|
||||||
&elm_a, &elm_b)) {
|
&elm_a, &elm_b)) {
|
||||||
|
extent_unlock(tsdn, extent);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -817,7 +861,7 @@ extent_deregister_impl(tsdn_t *tsdn, extent_t *extent, bool gdump) {
|
|||||||
|
|
||||||
extent_lock(tsdn, extent);
|
extent_lock(tsdn, extent);
|
||||||
|
|
||||||
extent_rtree_write_acquired(tsdn, elm_a, elm_b, NULL, NSIZES, false);
|
extent_rtree_write_acquired(tsdn, elm_a, elm_b, NULL, SC_NSIZES, false);
|
||||||
if (extent_slab_get(extent)) {
|
if (extent_slab_get(extent)) {
|
||||||
extent_interior_deregister(tsdn, rtree_ctx, extent);
|
extent_interior_deregister(tsdn, rtree_ctx, extent);
|
||||||
extent_slab_set(extent, false);
|
extent_slab_set(extent, false);
|
||||||
@ -874,7 +918,8 @@ extent_recycle_extract(tsdn_t *tsdn, arena_t *arena,
|
|||||||
extent_hooks_assure_initialized(arena, r_extent_hooks);
|
extent_hooks_assure_initialized(arena, r_extent_hooks);
|
||||||
extent_t *extent;
|
extent_t *extent;
|
||||||
if (new_addr != NULL) {
|
if (new_addr != NULL) {
|
||||||
extent = extent_lock_from_addr(tsdn, rtree_ctx, new_addr);
|
extent = extent_lock_from_addr(tsdn, rtree_ctx, new_addr,
|
||||||
|
false);
|
||||||
if (extent != NULL) {
|
if (extent != NULL) {
|
||||||
/*
|
/*
|
||||||
* We might null-out extent to report an error, but we
|
* We might null-out extent to report an error, but we
|
||||||
@ -958,7 +1003,7 @@ extent_split_interior(tsdn_t *tsdn, arena_t *arena,
|
|||||||
if (leadsize != 0) {
|
if (leadsize != 0) {
|
||||||
*lead = *extent;
|
*lead = *extent;
|
||||||
*extent = extent_split_impl(tsdn, arena, r_extent_hooks,
|
*extent = extent_split_impl(tsdn, arena, r_extent_hooks,
|
||||||
*lead, leadsize, NSIZES, false, esize + trailsize, szind,
|
*lead, leadsize, SC_NSIZES, false, esize + trailsize, szind,
|
||||||
slab, growing_retained);
|
slab, growing_retained);
|
||||||
if (*extent == NULL) {
|
if (*extent == NULL) {
|
||||||
*to_leak = *lead;
|
*to_leak = *lead;
|
||||||
@ -970,7 +1015,7 @@ extent_split_interior(tsdn_t *tsdn, arena_t *arena,
|
|||||||
/* Split the trail. */
|
/* Split the trail. */
|
||||||
if (trailsize != 0) {
|
if (trailsize != 0) {
|
||||||
*trail = extent_split_impl(tsdn, arena, r_extent_hooks, *extent,
|
*trail = extent_split_impl(tsdn, arena, r_extent_hooks, *extent,
|
||||||
esize, szind, slab, trailsize, NSIZES, false,
|
esize, szind, slab, trailsize, SC_NSIZES, false,
|
||||||
growing_retained);
|
growing_retained);
|
||||||
if (*trail == NULL) {
|
if (*trail == NULL) {
|
||||||
*to_leak = *extent;
|
*to_leak = *extent;
|
||||||
@ -987,7 +1032,7 @@ extent_split_interior(tsdn_t *tsdn, arena_t *arena,
|
|||||||
* splitting occurred.
|
* splitting occurred.
|
||||||
*/
|
*/
|
||||||
extent_szind_set(*extent, szind);
|
extent_szind_set(*extent, szind);
|
||||||
if (szind != NSIZES) {
|
if (szind != SC_NSIZES) {
|
||||||
rtree_szind_slab_update(tsdn, &extents_rtree, rtree_ctx,
|
rtree_szind_slab_update(tsdn, &extents_rtree, rtree_ctx,
|
||||||
(uintptr_t)extent_addr_get(*extent), szind, slab);
|
(uintptr_t)extent_addr_get(*extent), szind, slab);
|
||||||
if (slab && extent_size_get(*extent) > PAGE) {
|
if (slab && extent_size_get(*extent) > PAGE) {
|
||||||
@ -1023,6 +1068,17 @@ extent_recycle_split(tsdn_t *tsdn, arena_t *arena,
|
|||||||
&to_leak, &to_salvage, new_addr, size, pad, alignment, slab, szind,
|
&to_leak, &to_salvage, new_addr, size, pad, alignment, slab, szind,
|
||||||
growing_retained);
|
growing_retained);
|
||||||
|
|
||||||
|
if (!maps_coalesce && result != extent_split_interior_ok
|
||||||
|
&& !opt_retain) {
|
||||||
|
/*
|
||||||
|
* Split isn't supported (implies Windows w/o retain). Avoid
|
||||||
|
* leaking the extents.
|
||||||
|
*/
|
||||||
|
assert(to_leak != NULL && lead == NULL && trail == NULL);
|
||||||
|
extent_deactivate(tsdn, arena, extents, to_leak);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (result == extent_split_interior_ok) {
|
if (result == extent_split_interior_ok) {
|
||||||
if (lead != NULL) {
|
if (lead != NULL) {
|
||||||
extent_deactivate(tsdn, arena, extents, lead);
|
extent_deactivate(tsdn, arena, extents, lead);
|
||||||
@ -1043,16 +1099,27 @@ extent_recycle_split(tsdn_t *tsdn, arena_t *arena,
|
|||||||
if (to_leak != NULL) {
|
if (to_leak != NULL) {
|
||||||
void *leak = extent_base_get(to_leak);
|
void *leak = extent_base_get(to_leak);
|
||||||
extent_deregister_no_gdump_sub(tsdn, to_leak);
|
extent_deregister_no_gdump_sub(tsdn, to_leak);
|
||||||
extents_leak(tsdn, arena, r_extent_hooks, extents,
|
extents_abandon_vm(tsdn, arena, r_extent_hooks, extents,
|
||||||
to_leak, growing_retained);
|
to_leak, growing_retained);
|
||||||
assert(extent_lock_from_addr(tsdn, rtree_ctx, leak)
|
assert(extent_lock_from_addr(tsdn, rtree_ctx, leak,
|
||||||
== NULL);
|
false) == NULL);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
unreachable();
|
unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
extent_need_manual_zero(arena_t *arena) {
|
||||||
|
/*
|
||||||
|
* Need to manually zero the extent on repopulating if either; 1) non
|
||||||
|
* default extent hooks installed (in which case the purge semantics may
|
||||||
|
* change); or 2) transparent huge pages enabled.
|
||||||
|
*/
|
||||||
|
return (!arena_has_default_hooks(arena) ||
|
||||||
|
(opt_thp == thp_mode_always));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tries to satisfy the given allocation request by reusing one of the extents
|
* Tries to satisfy the given allocation request by reusing one of the extents
|
||||||
* in the given extents_t.
|
* in the given extents_t.
|
||||||
@ -1092,8 +1159,10 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks,
|
|||||||
extent, growing_retained);
|
extent, growing_retained);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (!extent_need_manual_zero(arena)) {
|
||||||
extent_zeroed_set(extent, true);
|
extent_zeroed_set(extent, true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (extent_committed_get(extent)) {
|
if (extent_committed_get(extent)) {
|
||||||
*commit = true;
|
*commit = true;
|
||||||
@ -1113,14 +1182,16 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks,
|
|||||||
|
|
||||||
if (*zero) {
|
if (*zero) {
|
||||||
void *addr = extent_base_get(extent);
|
void *addr = extent_base_get(extent);
|
||||||
size_t size = extent_size_get(extent);
|
|
||||||
if (!extent_zeroed_get(extent)) {
|
if (!extent_zeroed_get(extent)) {
|
||||||
if (pages_purge_forced(addr, size)) {
|
size_t size = extent_size_get(extent);
|
||||||
|
if (extent_need_manual_zero(arena) ||
|
||||||
|
pages_purge_forced(addr, size)) {
|
||||||
memset(addr, 0, size);
|
memset(addr, 0, size);
|
||||||
}
|
}
|
||||||
} else if (config_debug) {
|
} else if (config_debug) {
|
||||||
size_t *p = (size_t *)(uintptr_t)addr;
|
size_t *p = (size_t *)(uintptr_t)addr;
|
||||||
for (size_t i = 0; i < size / sizeof(size_t); i++) {
|
/* Check the first page only. */
|
||||||
|
for (size_t i = 0; i < PAGE / sizeof(size_t); i++) {
|
||||||
assert(p[i] == 0);
|
assert(p[i] == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1191,7 +1262,7 @@ extent_alloc_default(extent_hooks_t *extent_hooks, void *new_addr, size_t size,
|
|||||||
assert(arena != NULL);
|
assert(arena != NULL);
|
||||||
|
|
||||||
return extent_alloc_default_impl(tsdn, arena, new_addr, size,
|
return extent_alloc_default_impl(tsdn, arena, new_addr, size,
|
||||||
alignment, zero, commit);
|
ALIGNMENT_CEILING(alignment, PAGE), zero, commit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1244,11 +1315,11 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena,
|
|||||||
size_t alloc_size = sz_pind2sz(arena->extent_grow_next + egn_skip);
|
size_t alloc_size = sz_pind2sz(arena->extent_grow_next + egn_skip);
|
||||||
while (alloc_size < alloc_size_min) {
|
while (alloc_size < alloc_size_min) {
|
||||||
egn_skip++;
|
egn_skip++;
|
||||||
if (arena->extent_grow_next + egn_skip == NPSIZES) {
|
if (arena->extent_grow_next + egn_skip >=
|
||||||
|
sz_psz2ind(SC_LARGE_MAXCLASS)) {
|
||||||
/* Outside legal range. */
|
/* Outside legal range. */
|
||||||
goto label_err;
|
goto label_err;
|
||||||
}
|
}
|
||||||
assert(arena->extent_grow_next + egn_skip < NPSIZES);
|
|
||||||
alloc_size = sz_pind2sz(arena->extent_grow_next + egn_skip);
|
alloc_size = sz_pind2sz(arena->extent_grow_next + egn_skip);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1271,17 +1342,16 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena,
|
|||||||
extent_hook_post_reentrancy(tsdn);
|
extent_hook_post_reentrancy(tsdn);
|
||||||
}
|
}
|
||||||
|
|
||||||
extent_init(extent, arena, ptr, alloc_size, false, NSIZES,
|
extent_init(extent, arena, ptr, alloc_size, false, SC_NSIZES,
|
||||||
arena_extent_sn_next(arena), extent_state_active, zeroed,
|
arena_extent_sn_next(arena), extent_state_active, zeroed,
|
||||||
committed, true);
|
committed, true, EXTENT_IS_HEAD);
|
||||||
if (ptr == NULL) {
|
if (ptr == NULL) {
|
||||||
extent_dalloc(tsdn, arena, extent);
|
extent_dalloc(tsdn, arena, extent);
|
||||||
goto label_err;
|
goto label_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extent_register_no_gdump_add(tsdn, extent)) {
|
if (extent_register_no_gdump_add(tsdn, extent)) {
|
||||||
extents_leak(tsdn, arena, r_extent_hooks,
|
extent_dalloc(tsdn, arena, extent);
|
||||||
&arena->extents_retained, extent, true);
|
|
||||||
goto label_err;
|
goto label_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1328,7 +1398,7 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena,
|
|||||||
}
|
}
|
||||||
if (to_leak != NULL) {
|
if (to_leak != NULL) {
|
||||||
extent_deregister_no_gdump_sub(tsdn, to_leak);
|
extent_deregister_no_gdump_sub(tsdn, to_leak);
|
||||||
extents_leak(tsdn, arena, r_extent_hooks,
|
extents_abandon_vm(tsdn, arena, r_extent_hooks,
|
||||||
&arena->extents_retained, to_leak, true);
|
&arena->extents_retained, to_leak, true);
|
||||||
}
|
}
|
||||||
goto label_err;
|
goto label_err;
|
||||||
@ -1341,8 +1411,10 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena,
|
|||||||
&arena->extents_retained, extent, true);
|
&arena->extents_retained, extent, true);
|
||||||
goto label_err;
|
goto label_err;
|
||||||
}
|
}
|
||||||
|
if (!extent_need_manual_zero(arena)) {
|
||||||
extent_zeroed_set(extent, true);
|
extent_zeroed_set(extent, true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Increment extent_grow_next if doing so wouldn't exceed the allowed
|
* Increment extent_grow_next if doing so wouldn't exceed the allowed
|
||||||
@ -1375,7 +1447,8 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena,
|
|||||||
if (*zero && !extent_zeroed_get(extent)) {
|
if (*zero && !extent_zeroed_get(extent)) {
|
||||||
void *addr = extent_base_get(extent);
|
void *addr = extent_base_get(extent);
|
||||||
size_t size = extent_size_get(extent);
|
size_t size = extent_size_get(extent);
|
||||||
if (pages_purge_forced(addr, size)) {
|
if (extent_need_manual_zero(arena) ||
|
||||||
|
pages_purge_forced(addr, size)) {
|
||||||
memset(addr, 0, size);
|
memset(addr, 0, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1425,14 +1498,15 @@ extent_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
void *addr;
|
void *addr;
|
||||||
|
size_t palignment = ALIGNMENT_CEILING(alignment, PAGE);
|
||||||
if (*r_extent_hooks == &extent_hooks_default) {
|
if (*r_extent_hooks == &extent_hooks_default) {
|
||||||
/* Call directly to propagate tsdn. */
|
/* Call directly to propagate tsdn. */
|
||||||
addr = extent_alloc_default_impl(tsdn, arena, new_addr, esize,
|
addr = extent_alloc_default_impl(tsdn, arena, new_addr, esize,
|
||||||
alignment, zero, commit);
|
palignment, zero, commit);
|
||||||
} else {
|
} else {
|
||||||
extent_hook_pre_reentrancy(tsdn, arena);
|
extent_hook_pre_reentrancy(tsdn, arena);
|
||||||
addr = (*r_extent_hooks)->alloc(*r_extent_hooks, new_addr,
|
addr = (*r_extent_hooks)->alloc(*r_extent_hooks, new_addr,
|
||||||
esize, alignment, zero, commit, arena_ind_get(arena));
|
esize, palignment, zero, commit, arena_ind_get(arena));
|
||||||
extent_hook_post_reentrancy(tsdn);
|
extent_hook_post_reentrancy(tsdn);
|
||||||
}
|
}
|
||||||
if (addr == NULL) {
|
if (addr == NULL) {
|
||||||
@ -1441,13 +1515,12 @@ extent_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena,
|
|||||||
}
|
}
|
||||||
extent_init(extent, arena, addr, esize, slab, szind,
|
extent_init(extent, arena, addr, esize, slab, szind,
|
||||||
arena_extent_sn_next(arena), extent_state_active, *zero, *commit,
|
arena_extent_sn_next(arena), extent_state_active, *zero, *commit,
|
||||||
true);
|
true, EXTENT_NOT_HEAD);
|
||||||
if (pad != 0) {
|
if (pad != 0) {
|
||||||
extent_addr_randomize(tsdn, extent, alignment);
|
extent_addr_randomize(tsdn, extent, alignment);
|
||||||
}
|
}
|
||||||
if (extent_register(tsdn, extent)) {
|
if (extent_register(tsdn, extent)) {
|
||||||
extents_leak(tsdn, arena, r_extent_hooks,
|
extent_dalloc(tsdn, arena, extent);
|
||||||
&arena->extents_retained, extent, false);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1524,9 +1597,15 @@ extent_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static extent_t *
|
static extent_t *
|
||||||
extent_try_coalesce(tsdn_t *tsdn, arena_t *arena,
|
extent_try_coalesce_impl(tsdn_t *tsdn, arena_t *arena,
|
||||||
extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents,
|
extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents,
|
||||||
extent_t *extent, bool *coalesced, bool growing_retained) {
|
extent_t *extent, bool *coalesced, bool growing_retained,
|
||||||
|
bool inactive_only) {
|
||||||
|
/*
|
||||||
|
* We avoid checking / locking inactive neighbors for large size
|
||||||
|
* classes, since they are eagerly coalesced on deallocation which can
|
||||||
|
* cause lock contention.
|
||||||
|
*/
|
||||||
/*
|
/*
|
||||||
* Continue attempting to coalesce until failure, to protect against
|
* Continue attempting to coalesce until failure, to protect against
|
||||||
* races with other threads that are thwarted by this one.
|
* races with other threads that are thwarted by this one.
|
||||||
@ -1537,7 +1616,7 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena,
|
|||||||
|
|
||||||
/* Try to coalesce forward. */
|
/* Try to coalesce forward. */
|
||||||
extent_t *next = extent_lock_from_addr(tsdn, rtree_ctx,
|
extent_t *next = extent_lock_from_addr(tsdn, rtree_ctx,
|
||||||
extent_past_get(extent));
|
extent_past_get(extent), inactive_only);
|
||||||
if (next != NULL) {
|
if (next != NULL) {
|
||||||
/*
|
/*
|
||||||
* extents->mtx only protects against races for
|
* extents->mtx only protects against races for
|
||||||
@ -1563,7 +1642,7 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena,
|
|||||||
|
|
||||||
/* Try to coalesce backward. */
|
/* Try to coalesce backward. */
|
||||||
extent_t *prev = extent_lock_from_addr(tsdn, rtree_ctx,
|
extent_t *prev = extent_lock_from_addr(tsdn, rtree_ctx,
|
||||||
extent_before_get(extent));
|
extent_before_get(extent), inactive_only);
|
||||||
if (prev != NULL) {
|
if (prev != NULL) {
|
||||||
bool can_coalesce = extent_can_coalesce(arena, extents,
|
bool can_coalesce = extent_can_coalesce(arena, extents,
|
||||||
extent, prev);
|
extent, prev);
|
||||||
@ -1589,6 +1668,22 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena,
|
|||||||
return extent;
|
return extent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static extent_t *
|
||||||
|
extent_try_coalesce(tsdn_t *tsdn, arena_t *arena,
|
||||||
|
extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents,
|
||||||
|
extent_t *extent, bool *coalesced, bool growing_retained) {
|
||||||
|
return extent_try_coalesce_impl(tsdn, arena, r_extent_hooks, rtree_ctx,
|
||||||
|
extents, extent, coalesced, growing_retained, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static extent_t *
|
||||||
|
extent_try_coalesce_large(tsdn_t *tsdn, arena_t *arena,
|
||||||
|
extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents,
|
||||||
|
extent_t *extent, bool *coalesced, bool growing_retained) {
|
||||||
|
return extent_try_coalesce_impl(tsdn, arena, r_extent_hooks, rtree_ctx,
|
||||||
|
extents, extent, coalesced, growing_retained, true);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Does the metadata management portions of putting an unused extent into the
|
* Does the metadata management portions of putting an unused extent into the
|
||||||
* given extents_t (coalesces, deregisters slab interiors, the heap operations).
|
* given extents_t (coalesces, deregisters slab interiors, the heap operations).
|
||||||
@ -1606,7 +1701,7 @@ extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks,
|
|||||||
malloc_mutex_lock(tsdn, &extents->mtx);
|
malloc_mutex_lock(tsdn, &extents->mtx);
|
||||||
extent_hooks_assure_initialized(arena, r_extent_hooks);
|
extent_hooks_assure_initialized(arena, r_extent_hooks);
|
||||||
|
|
||||||
extent_szind_set(extent, NSIZES);
|
extent_szind_set(extent, SC_NSIZES);
|
||||||
if (extent_slab_get(extent)) {
|
if (extent_slab_get(extent)) {
|
||||||
extent_interior_deregister(tsdn, rtree_ctx, extent);
|
extent_interior_deregister(tsdn, rtree_ctx, extent);
|
||||||
extent_slab_set(extent, false);
|
extent_slab_set(extent, false);
|
||||||
@ -1618,18 +1713,22 @@ extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks,
|
|||||||
if (!extents->delay_coalesce) {
|
if (!extents->delay_coalesce) {
|
||||||
extent = extent_try_coalesce(tsdn, arena, r_extent_hooks,
|
extent = extent_try_coalesce(tsdn, arena, r_extent_hooks,
|
||||||
rtree_ctx, extents, extent, NULL, growing_retained);
|
rtree_ctx, extents, extent, NULL, growing_retained);
|
||||||
} else if (extent_size_get(extent) >= LARGE_MINCLASS) {
|
} else if (extent_size_get(extent) >= SC_LARGE_MINCLASS) {
|
||||||
|
assert(extents == &arena->extents_dirty);
|
||||||
/* Always coalesce large extents eagerly. */
|
/* Always coalesce large extents eagerly. */
|
||||||
bool coalesced;
|
bool coalesced;
|
||||||
size_t prev_size;
|
|
||||||
do {
|
do {
|
||||||
prev_size = extent_size_get(extent);
|
|
||||||
assert(extent_state_get(extent) == extent_state_active);
|
assert(extent_state_get(extent) == extent_state_active);
|
||||||
extent = extent_try_coalesce(tsdn, arena,
|
extent = extent_try_coalesce_large(tsdn, arena,
|
||||||
r_extent_hooks, rtree_ctx, extents, extent,
|
r_extent_hooks, rtree_ctx, extents, extent,
|
||||||
&coalesced, growing_retained);
|
&coalesced, growing_retained);
|
||||||
} while (coalesced &&
|
} while (coalesced);
|
||||||
extent_size_get(extent) >= prev_size + LARGE_MINCLASS);
|
if (extent_size_get(extent) >= oversize_threshold) {
|
||||||
|
/* Shortcut to purge the oversize extent eagerly. */
|
||||||
|
malloc_mutex_unlock(tsdn, &extents->mtx);
|
||||||
|
arena_decay_extent(tsdn, arena, r_extent_hooks, extent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
extent_deactivate_locked(tsdn, arena, extents, extent);
|
extent_deactivate_locked(tsdn, arena, extents, extent);
|
||||||
|
|
||||||
@ -1644,13 +1743,18 @@ extent_dalloc_gap(tsdn_t *tsdn, arena_t *arena, extent_t *extent) {
|
|||||||
WITNESS_RANK_CORE, 0);
|
WITNESS_RANK_CORE, 0);
|
||||||
|
|
||||||
if (extent_register(tsdn, extent)) {
|
if (extent_register(tsdn, extent)) {
|
||||||
extents_leak(tsdn, arena, &extent_hooks,
|
extent_dalloc(tsdn, arena, extent);
|
||||||
&arena->extents_retained, extent, false);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
extent_dalloc_wrapper(tsdn, arena, &extent_hooks, extent);
|
extent_dalloc_wrapper(tsdn, arena, &extent_hooks, extent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
extent_may_dalloc(void) {
|
||||||
|
/* With retain enabled, the default dalloc always fails. */
|
||||||
|
return !opt_retain;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
extent_dalloc_default_impl(void *addr, size_t size) {
|
extent_dalloc_default_impl(void *addr, size_t size) {
|
||||||
if (!have_dss || !extent_in_dss(addr)) {
|
if (!have_dss || !extent_in_dss(addr)) {
|
||||||
@ -1706,16 +1810,20 @@ extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena,
|
|||||||
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
||||||
WITNESS_RANK_CORE, 0);
|
WITNESS_RANK_CORE, 0);
|
||||||
|
|
||||||
|
/* Avoid calling the default extent_dalloc unless have to. */
|
||||||
|
if (*r_extent_hooks != &extent_hooks_default || extent_may_dalloc()) {
|
||||||
/*
|
/*
|
||||||
* Deregister first to avoid a race with other allocating threads, and
|
* Deregister first to avoid a race with other allocating
|
||||||
* reregister if deallocation fails.
|
* threads, and reregister if deallocation fails.
|
||||||
*/
|
*/
|
||||||
extent_deregister(tsdn, extent);
|
extent_deregister(tsdn, extent);
|
||||||
if (!extent_dalloc_wrapper_try(tsdn, arena, r_extent_hooks, extent)) {
|
if (!extent_dalloc_wrapper_try(tsdn, arena, r_extent_hooks,
|
||||||
|
extent)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
extent_reregister(tsdn, extent);
|
extent_reregister(tsdn, extent);
|
||||||
|
}
|
||||||
|
|
||||||
if (*r_extent_hooks != &extent_hooks_default) {
|
if (*r_extent_hooks != &extent_hooks_default) {
|
||||||
extent_hook_pre_reentrancy(tsdn, arena);
|
extent_hook_pre_reentrancy(tsdn, arena);
|
||||||
}
|
}
|
||||||
@ -1955,13 +2063,20 @@ extent_purge_forced_wrapper(tsdn_t *tsdn, arena_t *arena,
|
|||||||
offset, length, false);
|
offset, length, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JEMALLOC_MAPS_COALESCE
|
|
||||||
static bool
|
static bool
|
||||||
extent_split_default(extent_hooks_t *extent_hooks, void *addr, size_t size,
|
extent_split_default(extent_hooks_t *extent_hooks, void *addr, size_t size,
|
||||||
size_t size_a, size_t size_b, bool committed, unsigned arena_ind) {
|
size_t size_a, size_t size_b, bool committed, unsigned arena_ind) {
|
||||||
return !maps_coalesce;
|
if (!maps_coalesce) {
|
||||||
|
/*
|
||||||
|
* Without retain, only whole regions can be purged (required by
|
||||||
|
* MEM_RELEASE on Windows) -- therefore disallow splitting. See
|
||||||
|
* comments in extent_head_no_merge().
|
||||||
|
*/
|
||||||
|
return !opt_retain;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Accepts the extent to split, and the characteristics of each side of the
|
* Accepts the extent to split, and the characteristics of each side of the
|
||||||
@ -1993,7 +2108,8 @@ extent_split_impl(tsdn_t *tsdn, arena_t *arena,
|
|||||||
extent_init(trail, arena, (void *)((uintptr_t)extent_base_get(extent) +
|
extent_init(trail, arena, (void *)((uintptr_t)extent_base_get(extent) +
|
||||||
size_a), size_b, slab_b, szind_b, extent_sn_get(extent),
|
size_a), size_b, slab_b, szind_b, extent_sn_get(extent),
|
||||||
extent_state_get(extent), extent_zeroed_get(extent),
|
extent_state_get(extent), extent_zeroed_get(extent),
|
||||||
extent_committed_get(extent), extent_dumpable_get(extent));
|
extent_committed_get(extent), extent_dumpable_get(extent),
|
||||||
|
EXTENT_NOT_HEAD);
|
||||||
|
|
||||||
rtree_ctx_t rtree_ctx_fallback;
|
rtree_ctx_t rtree_ctx_fallback;
|
||||||
rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
|
rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
|
||||||
@ -2004,7 +2120,8 @@ extent_split_impl(tsdn_t *tsdn, arena_t *arena,
|
|||||||
extent_init(&lead, arena, extent_addr_get(extent), size_a,
|
extent_init(&lead, arena, extent_addr_get(extent), size_a,
|
||||||
slab_a, szind_a, extent_sn_get(extent),
|
slab_a, szind_a, extent_sn_get(extent),
|
||||||
extent_state_get(extent), extent_zeroed_get(extent),
|
extent_state_get(extent), extent_zeroed_get(extent),
|
||||||
extent_committed_get(extent), extent_dumpable_get(extent));
|
extent_committed_get(extent), extent_dumpable_get(extent),
|
||||||
|
EXTENT_NOT_HEAD);
|
||||||
|
|
||||||
extent_rtree_leaf_elms_lookup(tsdn, rtree_ctx, &lead, false,
|
extent_rtree_leaf_elms_lookup(tsdn, rtree_ctx, &lead, false,
|
||||||
true, &lead_elm_a, &lead_elm_b);
|
true, &lead_elm_a, &lead_elm_b);
|
||||||
@ -2062,7 +2179,7 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena,
|
|||||||
|
|
||||||
static bool
|
static bool
|
||||||
extent_merge_default_impl(void *addr_a, void *addr_b) {
|
extent_merge_default_impl(void *addr_a, void *addr_b) {
|
||||||
if (!maps_coalesce) {
|
if (!maps_coalesce && !opt_retain) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (have_dss && !extent_dss_mergeable(addr_a, addr_b)) {
|
if (have_dss && !extent_dss_mergeable(addr_a, addr_b)) {
|
||||||
@ -2072,13 +2189,51 @@ extent_merge_default_impl(void *addr_a, void *addr_b) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JEMALLOC_MAPS_COALESCE
|
/*
|
||||||
|
* Returns true if the given extents can't be merged because of their head bit
|
||||||
|
* settings. Assumes the second extent has the higher address.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
extent_head_no_merge(extent_t *a, extent_t *b) {
|
||||||
|
assert(extent_base_get(a) < extent_base_get(b));
|
||||||
|
/*
|
||||||
|
* When coalesce is not always allowed (Windows), only merge extents
|
||||||
|
* from the same VirtualAlloc region under opt.retain (in which case
|
||||||
|
* MEM_DECOMMIT is utilized for purging).
|
||||||
|
*/
|
||||||
|
if (maps_coalesce) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!opt_retain) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/* If b is a head extent, disallow the cross-region merge. */
|
||||||
|
if (extent_is_head_get(b)) {
|
||||||
|
/*
|
||||||
|
* Additionally, sn should not overflow with retain; sanity
|
||||||
|
* check that different regions have unique sn.
|
||||||
|
*/
|
||||||
|
assert(extent_sn_comp(a, b) != 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
assert(extent_sn_comp(a, b) == 0);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a,
|
extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a,
|
||||||
void *addr_b, size_t size_b, bool committed, unsigned arena_ind) {
|
void *addr_b, size_t size_b, bool committed, unsigned arena_ind) {
|
||||||
|
if (!maps_coalesce) {
|
||||||
|
tsdn_t *tsdn = tsdn_fetch();
|
||||||
|
extent_t *a = iealloc(tsdn, addr_a);
|
||||||
|
extent_t *b = iealloc(tsdn, addr_b);
|
||||||
|
if (extent_head_no_merge(a, b)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
return extent_merge_default_impl(addr_a, addr_b);
|
return extent_merge_default_impl(addr_a, addr_b);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
extent_merge_impl(tsdn_t *tsdn, arena_t *arena,
|
extent_merge_impl(tsdn_t *tsdn, arena_t *arena,
|
||||||
@ -2086,10 +2241,11 @@ extent_merge_impl(tsdn_t *tsdn, arena_t *arena,
|
|||||||
bool growing_retained) {
|
bool growing_retained) {
|
||||||
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
||||||
WITNESS_RANK_CORE, growing_retained ? 1 : 0);
|
WITNESS_RANK_CORE, growing_retained ? 1 : 0);
|
||||||
|
assert(extent_base_get(a) < extent_base_get(b));
|
||||||
|
|
||||||
extent_hooks_assure_initialized(arena, r_extent_hooks);
|
extent_hooks_assure_initialized(arena, r_extent_hooks);
|
||||||
|
|
||||||
if ((*r_extent_hooks)->merge == NULL) {
|
if ((*r_extent_hooks)->merge == NULL || extent_head_no_merge(a, b)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2128,22 +2284,23 @@ extent_merge_impl(tsdn_t *tsdn, arena_t *arena,
|
|||||||
|
|
||||||
if (a_elm_b != NULL) {
|
if (a_elm_b != NULL) {
|
||||||
rtree_leaf_elm_write(tsdn, &extents_rtree, a_elm_b, NULL,
|
rtree_leaf_elm_write(tsdn, &extents_rtree, a_elm_b, NULL,
|
||||||
NSIZES, false);
|
SC_NSIZES, false);
|
||||||
}
|
}
|
||||||
if (b_elm_b != NULL) {
|
if (b_elm_b != NULL) {
|
||||||
rtree_leaf_elm_write(tsdn, &extents_rtree, b_elm_a, NULL,
|
rtree_leaf_elm_write(tsdn, &extents_rtree, b_elm_a, NULL,
|
||||||
NSIZES, false);
|
SC_NSIZES, false);
|
||||||
} else {
|
} else {
|
||||||
b_elm_b = b_elm_a;
|
b_elm_b = b_elm_a;
|
||||||
}
|
}
|
||||||
|
|
||||||
extent_size_set(a, extent_size_get(a) + extent_size_get(b));
|
extent_size_set(a, extent_size_get(a) + extent_size_get(b));
|
||||||
extent_szind_set(a, NSIZES);
|
extent_szind_set(a, SC_NSIZES);
|
||||||
extent_sn_set(a, (extent_sn_get(a) < extent_sn_get(b)) ?
|
extent_sn_set(a, (extent_sn_get(a) < extent_sn_get(b)) ?
|
||||||
extent_sn_get(a) : extent_sn_get(b));
|
extent_sn_get(a) : extent_sn_get(b));
|
||||||
extent_zeroed_set(a, extent_zeroed_get(a) && extent_zeroed_get(b));
|
extent_zeroed_set(a, extent_zeroed_get(a) && extent_zeroed_get(b));
|
||||||
|
|
||||||
extent_rtree_write_acquired(tsdn, a_elm_a, b_elm_b, a, NSIZES, false);
|
extent_rtree_write_acquired(tsdn, a_elm_a, b_elm_b, a, SC_NSIZES,
|
||||||
|
false);
|
||||||
|
|
||||||
extent_unlock2(tsdn, a, b);
|
extent_unlock2(tsdn, a, b);
|
||||||
|
|
||||||
@ -2175,3 +2332,72 @@ extent_boot(void) {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
extent_util_stats_get(tsdn_t *tsdn, const void *ptr,
|
||||||
|
size_t *nfree, size_t *nregs, size_t *size) {
|
||||||
|
assert(ptr != NULL && nfree != NULL && nregs != NULL && size != NULL);
|
||||||
|
|
||||||
|
const extent_t *extent = iealloc(tsdn, ptr);
|
||||||
|
if (unlikely(extent == NULL)) {
|
||||||
|
*nfree = *nregs = *size = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*size = extent_size_get(extent);
|
||||||
|
if (!extent_slab_get(extent)) {
|
||||||
|
*nfree = 0;
|
||||||
|
*nregs = 1;
|
||||||
|
} else {
|
||||||
|
*nfree = extent_nfree_get(extent);
|
||||||
|
*nregs = bin_infos[extent_szind_get(extent)].nregs;
|
||||||
|
assert(*nfree <= *nregs);
|
||||||
|
assert(*nfree * extent_usize_get(extent) <= *size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
extent_util_stats_verbose_get(tsdn_t *tsdn, const void *ptr,
|
||||||
|
size_t *nfree, size_t *nregs, size_t *size,
|
||||||
|
size_t *bin_nfree, size_t *bin_nregs, void **slabcur_addr) {
|
||||||
|
assert(ptr != NULL && nfree != NULL && nregs != NULL && size != NULL
|
||||||
|
&& bin_nfree != NULL && bin_nregs != NULL && slabcur_addr != NULL);
|
||||||
|
|
||||||
|
const extent_t *extent = iealloc(tsdn, ptr);
|
||||||
|
if (unlikely(extent == NULL)) {
|
||||||
|
*nfree = *nregs = *size = *bin_nfree = *bin_nregs = 0;
|
||||||
|
*slabcur_addr = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*size = extent_size_get(extent);
|
||||||
|
if (!extent_slab_get(extent)) {
|
||||||
|
*nfree = *bin_nfree = *bin_nregs = 0;
|
||||||
|
*nregs = 1;
|
||||||
|
*slabcur_addr = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*nfree = extent_nfree_get(extent);
|
||||||
|
const szind_t szind = extent_szind_get(extent);
|
||||||
|
*nregs = bin_infos[szind].nregs;
|
||||||
|
assert(*nfree <= *nregs);
|
||||||
|
assert(*nfree * extent_usize_get(extent) <= *size);
|
||||||
|
|
||||||
|
const arena_t *arena = extent_arena_get(extent);
|
||||||
|
assert(arena != NULL);
|
||||||
|
const unsigned binshard = extent_binshard_get(extent);
|
||||||
|
bin_t *bin = &arena->bins[szind].bin_shards[binshard];
|
||||||
|
|
||||||
|
malloc_mutex_lock(tsdn, &bin->lock);
|
||||||
|
if (config_stats) {
|
||||||
|
*bin_nregs = *nregs * bin->stats.curslabs;
|
||||||
|
assert(*bin_nregs >= bin->stats.curregs);
|
||||||
|
*bin_nfree = *bin_nregs - bin->stats.curregs;
|
||||||
|
} else {
|
||||||
|
*bin_nfree = *bin_nregs = 0;
|
||||||
|
}
|
||||||
|
*slabcur_addr = extent_addr_get(bin->slabcur);
|
||||||
|
assert(*slabcur_addr != NULL);
|
||||||
|
malloc_mutex_unlock(tsdn, &bin->lock);
|
||||||
|
}
|
||||||
|
11
deps/jemalloc/src/extent_dss.c
vendored
11
deps/jemalloc/src/extent_dss.c
vendored
@ -113,7 +113,7 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size,
|
|||||||
|
|
||||||
cassert(have_dss);
|
cassert(have_dss);
|
||||||
assert(size > 0);
|
assert(size > 0);
|
||||||
assert(alignment > 0);
|
assert(alignment == ALIGNMENT_CEILING(alignment, PAGE));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sbrk() uses a signed increment argument, so take care not to
|
* sbrk() uses a signed increment argument, so take care not to
|
||||||
@ -154,9 +154,10 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size,
|
|||||||
(uintptr_t)gap_addr_page;
|
(uintptr_t)gap_addr_page;
|
||||||
if (gap_size_page != 0) {
|
if (gap_size_page != 0) {
|
||||||
extent_init(gap, arena, gap_addr_page,
|
extent_init(gap, arena, gap_addr_page,
|
||||||
gap_size_page, false, NSIZES,
|
gap_size_page, false, SC_NSIZES,
|
||||||
arena_extent_sn_next(arena),
|
arena_extent_sn_next(arena),
|
||||||
extent_state_active, false, true, true);
|
extent_state_active, false, true, true,
|
||||||
|
EXTENT_NOT_HEAD);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Compute the address just past the end of the desired
|
* Compute the address just past the end of the desired
|
||||||
@ -198,9 +199,9 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size,
|
|||||||
extent_t extent;
|
extent_t extent;
|
||||||
|
|
||||||
extent_init(&extent, arena, ret, size,
|
extent_init(&extent, arena, ret, size,
|
||||||
size, false, NSIZES,
|
size, false, SC_NSIZES,
|
||||||
extent_state_active, false, true,
|
extent_state_active, false, true,
|
||||||
true);
|
true, EXTENT_NOT_HEAD);
|
||||||
if (extent_purge_forced_wrapper(tsdn,
|
if (extent_purge_forced_wrapper(tsdn,
|
||||||
arena, &extent_hooks, &extent, 0,
|
arena, &extent_hooks, &extent, 0,
|
||||||
size)) {
|
size)) {
|
||||||
|
4
deps/jemalloc/src/extent_mmap.c
vendored
4
deps/jemalloc/src/extent_mmap.c
vendored
@ -21,8 +21,8 @@ bool opt_retain =
|
|||||||
void *
|
void *
|
||||||
extent_alloc_mmap(void *new_addr, size_t size, size_t alignment, bool *zero,
|
extent_alloc_mmap(void *new_addr, size_t size, size_t alignment, bool *zero,
|
||||||
bool *commit) {
|
bool *commit) {
|
||||||
void *ret = pages_map(new_addr, size, ALIGNMENT_CEILING(alignment,
|
assert(alignment == ALIGNMENT_CEILING(alignment, PAGE));
|
||||||
PAGE), commit);
|
void *ret = pages_map(new_addr, size, alignment, commit);
|
||||||
if (ret == NULL) {
|
if (ret == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
195
deps/jemalloc/src/hook.c
vendored
Normal file
195
deps/jemalloc/src/hook.c
vendored
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
#include "jemalloc/internal/jemalloc_preamble.h"
|
||||||
|
|
||||||
|
#include "jemalloc/internal/hook.h"
|
||||||
|
|
||||||
|
#include "jemalloc/internal/atomic.h"
|
||||||
|
#include "jemalloc/internal/mutex.h"
|
||||||
|
#include "jemalloc/internal/seq.h"
|
||||||
|
|
||||||
|
typedef struct hooks_internal_s hooks_internal_t;
|
||||||
|
struct hooks_internal_s {
|
||||||
|
hooks_t hooks;
|
||||||
|
bool in_use;
|
||||||
|
};
|
||||||
|
|
||||||
|
seq_define(hooks_internal_t, hooks)
|
||||||
|
|
||||||
|
static atomic_u_t nhooks = ATOMIC_INIT(0);
|
||||||
|
static seq_hooks_t hooks[HOOK_MAX];
|
||||||
|
static malloc_mutex_t hooks_mu;
|
||||||
|
|
||||||
|
bool
|
||||||
|
hook_boot() {
|
||||||
|
return malloc_mutex_init(&hooks_mu, "hooks", WITNESS_RANK_HOOK,
|
||||||
|
malloc_mutex_rank_exclusive);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
hook_install_locked(hooks_t *to_install) {
|
||||||
|
hooks_internal_t hooks_internal;
|
||||||
|
for (int i = 0; i < HOOK_MAX; i++) {
|
||||||
|
bool success = seq_try_load_hooks(&hooks_internal, &hooks[i]);
|
||||||
|
/* We hold mu; no concurrent access. */
|
||||||
|
assert(success);
|
||||||
|
if (!hooks_internal.in_use) {
|
||||||
|
hooks_internal.hooks = *to_install;
|
||||||
|
hooks_internal.in_use = true;
|
||||||
|
seq_store_hooks(&hooks[i], &hooks_internal);
|
||||||
|
atomic_store_u(&nhooks,
|
||||||
|
atomic_load_u(&nhooks, ATOMIC_RELAXED) + 1,
|
||||||
|
ATOMIC_RELAXED);
|
||||||
|
return &hooks[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
hook_install(tsdn_t *tsdn, hooks_t *to_install) {
|
||||||
|
malloc_mutex_lock(tsdn, &hooks_mu);
|
||||||
|
void *ret = hook_install_locked(to_install);
|
||||||
|
if (ret != NULL) {
|
||||||
|
tsd_global_slow_inc(tsdn);
|
||||||
|
}
|
||||||
|
malloc_mutex_unlock(tsdn, &hooks_mu);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hook_remove_locked(seq_hooks_t *to_remove) {
|
||||||
|
hooks_internal_t hooks_internal;
|
||||||
|
bool success = seq_try_load_hooks(&hooks_internal, to_remove);
|
||||||
|
/* We hold mu; no concurrent access. */
|
||||||
|
assert(success);
|
||||||
|
/* Should only remove hooks that were added. */
|
||||||
|
assert(hooks_internal.in_use);
|
||||||
|
hooks_internal.in_use = false;
|
||||||
|
seq_store_hooks(to_remove, &hooks_internal);
|
||||||
|
atomic_store_u(&nhooks, atomic_load_u(&nhooks, ATOMIC_RELAXED) - 1,
|
||||||
|
ATOMIC_RELAXED);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hook_remove(tsdn_t *tsdn, void *opaque) {
|
||||||
|
if (config_debug) {
|
||||||
|
char *hooks_begin = (char *)&hooks[0];
|
||||||
|
char *hooks_end = (char *)&hooks[HOOK_MAX];
|
||||||
|
char *hook = (char *)opaque;
|
||||||
|
assert(hooks_begin <= hook && hook < hooks_end
|
||||||
|
&& (hook - hooks_begin) % sizeof(seq_hooks_t) == 0);
|
||||||
|
}
|
||||||
|
malloc_mutex_lock(tsdn, &hooks_mu);
|
||||||
|
hook_remove_locked((seq_hooks_t *)opaque);
|
||||||
|
tsd_global_slow_dec(tsdn);
|
||||||
|
malloc_mutex_unlock(tsdn, &hooks_mu);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FOR_EACH_HOOK_BEGIN(hooks_internal_ptr) \
|
||||||
|
for (int for_each_hook_counter = 0; \
|
||||||
|
for_each_hook_counter < HOOK_MAX; \
|
||||||
|
for_each_hook_counter++) { \
|
||||||
|
bool for_each_hook_success = seq_try_load_hooks( \
|
||||||
|
(hooks_internal_ptr), &hooks[for_each_hook_counter]); \
|
||||||
|
if (!for_each_hook_success) { \
|
||||||
|
continue; \
|
||||||
|
} \
|
||||||
|
if (!(hooks_internal_ptr)->in_use) { \
|
||||||
|
continue; \
|
||||||
|
}
|
||||||
|
#define FOR_EACH_HOOK_END \
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool *
|
||||||
|
hook_reentrantp() {
|
||||||
|
/*
|
||||||
|
* We prevent user reentrancy within hooks. This is basically just a
|
||||||
|
* thread-local bool that triggers an early-exit.
|
||||||
|
*
|
||||||
|
* We don't fold in_hook into reentrancy. There are two reasons for
|
||||||
|
* this:
|
||||||
|
* - Right now, we turn on reentrancy during things like extent hook
|
||||||
|
* execution. Allocating during extent hooks is not officially
|
||||||
|
* supported, but we don't want to break it for the time being. These
|
||||||
|
* sorts of allocations should probably still be hooked, though.
|
||||||
|
* - If a hook allocates, we may want it to be relatively fast (after
|
||||||
|
* all, it executes on every allocator operation). Turning on
|
||||||
|
* reentrancy is a fairly heavyweight mode (disabling tcache,
|
||||||
|
* redirecting to arena 0, etc.). It's possible we may one day want
|
||||||
|
* to turn on reentrant mode here, if it proves too difficult to keep
|
||||||
|
* this working. But that's fairly easy for us to see; OTOH, people
|
||||||
|
* not using hooks because they're too slow is easy for us to miss.
|
||||||
|
*
|
||||||
|
* The tricky part is
|
||||||
|
* that this code might get invoked even if we don't have access to tsd.
|
||||||
|
* This function mimics getting a pointer to thread-local data, except
|
||||||
|
* that it might secretly return a pointer to some global data if we
|
||||||
|
* know that the caller will take the early-exit path.
|
||||||
|
* If we return a bool that indicates that we are reentrant, then the
|
||||||
|
* caller will go down the early exit path, leaving the global
|
||||||
|
* untouched.
|
||||||
|
*/
|
||||||
|
static bool in_hook_global = true;
|
||||||
|
tsdn_t *tsdn = tsdn_fetch();
|
||||||
|
tcache_t *tcache = tsdn_tcachep_get(tsdn);
|
||||||
|
if (tcache != NULL) {
|
||||||
|
return &tcache->in_hook;
|
||||||
|
}
|
||||||
|
return &in_hook_global;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define HOOK_PROLOGUE \
|
||||||
|
if (likely(atomic_load_u(&nhooks, ATOMIC_RELAXED) == 0)) { \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
bool *in_hook = hook_reentrantp(); \
|
||||||
|
if (*in_hook) { \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
*in_hook = true;
|
||||||
|
|
||||||
|
#define HOOK_EPILOGUE \
|
||||||
|
*in_hook = false;
|
||||||
|
|
||||||
|
void
|
||||||
|
hook_invoke_alloc(hook_alloc_t type, void *result, uintptr_t result_raw,
|
||||||
|
uintptr_t args_raw[3]) {
|
||||||
|
HOOK_PROLOGUE
|
||||||
|
|
||||||
|
hooks_internal_t hook;
|
||||||
|
FOR_EACH_HOOK_BEGIN(&hook)
|
||||||
|
hook_alloc h = hook.hooks.alloc_hook;
|
||||||
|
if (h != NULL) {
|
||||||
|
h(hook.hooks.extra, type, result, result_raw, args_raw);
|
||||||
|
}
|
||||||
|
FOR_EACH_HOOK_END
|
||||||
|
|
||||||
|
HOOK_EPILOGUE
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hook_invoke_dalloc(hook_dalloc_t type, void *address, uintptr_t args_raw[3]) {
|
||||||
|
HOOK_PROLOGUE
|
||||||
|
hooks_internal_t hook;
|
||||||
|
FOR_EACH_HOOK_BEGIN(&hook)
|
||||||
|
hook_dalloc h = hook.hooks.dalloc_hook;
|
||||||
|
if (h != NULL) {
|
||||||
|
h(hook.hooks.extra, type, address, args_raw);
|
||||||
|
}
|
||||||
|
FOR_EACH_HOOK_END
|
||||||
|
HOOK_EPILOGUE
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hook_invoke_expand(hook_expand_t type, void *address, size_t old_usize,
|
||||||
|
size_t new_usize, uintptr_t result_raw, uintptr_t args_raw[4]) {
|
||||||
|
HOOK_PROLOGUE
|
||||||
|
hooks_internal_t hook;
|
||||||
|
FOR_EACH_HOOK_BEGIN(&hook)
|
||||||
|
hook_expand h = hook.hooks.expand_hook;
|
||||||
|
if (h != NULL) {
|
||||||
|
h(hook.hooks.extra, type, address, old_usize, new_usize,
|
||||||
|
result_raw, args_raw);
|
||||||
|
}
|
||||||
|
FOR_EACH_HOOK_END
|
||||||
|
HOOK_EPILOGUE
|
||||||
|
}
|
980
deps/jemalloc/src/jemalloc.c
vendored
980
deps/jemalloc/src/jemalloc.c
vendored
File diff suppressed because it is too large
Load Diff
4
deps/jemalloc/src/jemalloc_cpp.cpp
vendored
4
deps/jemalloc/src/jemalloc_cpp.cpp
vendored
@ -128,14 +128,14 @@ operator delete(void *ptr, std::size_t size) noexcept {
|
|||||||
if (unlikely(ptr == nullptr)) {
|
if (unlikely(ptr == nullptr)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
je_sdallocx(ptr, size, /*flags=*/0);
|
je_sdallocx_noflags(ptr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator delete[](void *ptr, std::size_t size) noexcept {
|
void operator delete[](void *ptr, std::size_t size) noexcept {
|
||||||
if (unlikely(ptr == nullptr)) {
|
if (unlikely(ptr == nullptr)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
je_sdallocx(ptr, size, /*flags=*/0);
|
je_sdallocx_noflags(ptr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // __cpp_sized_deallocation
|
#endif // __cpp_sized_deallocation
|
||||||
|
52
deps/jemalloc/src/large.c
vendored
52
deps/jemalloc/src/large.c
vendored
@ -28,7 +28,7 @@ large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment,
|
|||||||
assert(!tsdn_null(tsdn) || arena != NULL);
|
assert(!tsdn_null(tsdn) || arena != NULL);
|
||||||
|
|
||||||
ausize = sz_sa2u(usize, alignment);
|
ausize = sz_sa2u(usize, alignment);
|
||||||
if (unlikely(ausize == 0 || ausize > LARGE_MAXCLASS)) {
|
if (unlikely(ausize == 0 || ausize > SC_LARGE_MAXCLASS)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment,
|
|||||||
*/
|
*/
|
||||||
is_zeroed = zero;
|
is_zeroed = zero;
|
||||||
if (likely(!tsdn_null(tsdn))) {
|
if (likely(!tsdn_null(tsdn))) {
|
||||||
arena = arena_choose(tsdn_tsd(tsdn), arena);
|
arena = arena_choose_maybe_huge(tsdn_tsd(tsdn), arena, usize);
|
||||||
}
|
}
|
||||||
if (unlikely(arena == NULL) || (extent = arena_extent_alloc_large(tsdn,
|
if (unlikely(arena == NULL) || (extent = arena_extent_alloc_large(tsdn,
|
||||||
arena, usize, alignment, &is_zeroed)) == NULL) {
|
arena, usize, alignment, &is_zeroed)) == NULL) {
|
||||||
@ -109,7 +109,7 @@ large_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) {
|
|||||||
if (diff != 0) {
|
if (diff != 0) {
|
||||||
extent_t *trail = extent_split_wrapper(tsdn, arena,
|
extent_t *trail = extent_split_wrapper(tsdn, arena,
|
||||||
&extent_hooks, extent, usize + sz_large_pad,
|
&extent_hooks, extent, usize + sz_large_pad,
|
||||||
sz_size2index(usize), false, diff, NSIZES, false);
|
sz_size2index(usize), false, diff, SC_NSIZES, false);
|
||||||
if (trail == NULL) {
|
if (trail == NULL) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -154,17 +154,17 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize,
|
|||||||
bool new_mapping;
|
bool new_mapping;
|
||||||
if ((trail = extents_alloc(tsdn, arena, &extent_hooks,
|
if ((trail = extents_alloc(tsdn, arena, &extent_hooks,
|
||||||
&arena->extents_dirty, extent_past_get(extent), trailsize, 0,
|
&arena->extents_dirty, extent_past_get(extent), trailsize, 0,
|
||||||
CACHELINE, false, NSIZES, &is_zeroed_trail, &commit)) != NULL
|
CACHELINE, false, SC_NSIZES, &is_zeroed_trail, &commit)) != NULL
|
||||||
|| (trail = extents_alloc(tsdn, arena, &extent_hooks,
|
|| (trail = extents_alloc(tsdn, arena, &extent_hooks,
|
||||||
&arena->extents_muzzy, extent_past_get(extent), trailsize, 0,
|
&arena->extents_muzzy, extent_past_get(extent), trailsize, 0,
|
||||||
CACHELINE, false, NSIZES, &is_zeroed_trail, &commit)) != NULL) {
|
CACHELINE, false, SC_NSIZES, &is_zeroed_trail, &commit)) != NULL) {
|
||||||
if (config_stats) {
|
if (config_stats) {
|
||||||
new_mapping = false;
|
new_mapping = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ((trail = extent_alloc_wrapper(tsdn, arena, &extent_hooks,
|
if ((trail = extent_alloc_wrapper(tsdn, arena, &extent_hooks,
|
||||||
extent_past_get(extent), trailsize, 0, CACHELINE, false,
|
extent_past_get(extent), trailsize, 0, CACHELINE, false,
|
||||||
NSIZES, &is_zeroed_trail, &commit)) == NULL) {
|
SC_NSIZES, &is_zeroed_trail, &commit)) == NULL) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (config_stats) {
|
if (config_stats) {
|
||||||
@ -221,9 +221,10 @@ large_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min,
|
|||||||
size_t oldusize = extent_usize_get(extent);
|
size_t oldusize = extent_usize_get(extent);
|
||||||
|
|
||||||
/* The following should have been caught by callers. */
|
/* The following should have been caught by callers. */
|
||||||
assert(usize_min > 0 && usize_max <= LARGE_MAXCLASS);
|
assert(usize_min > 0 && usize_max <= SC_LARGE_MAXCLASS);
|
||||||
/* Both allocation sizes must be large to avoid a move. */
|
/* Both allocation sizes must be large to avoid a move. */
|
||||||
assert(oldusize >= LARGE_MINCLASS && usize_max >= LARGE_MINCLASS);
|
assert(oldusize >= SC_LARGE_MINCLASS
|
||||||
|
&& usize_max >= SC_LARGE_MINCLASS);
|
||||||
|
|
||||||
if (usize_max > oldusize) {
|
if (usize_max > oldusize) {
|
||||||
/* Attempt to expand the allocation in-place. */
|
/* Attempt to expand the allocation in-place. */
|
||||||
@ -270,17 +271,23 @@ large_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize,
|
large_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t usize,
|
||||||
size_t alignment, bool zero, tcache_t *tcache) {
|
size_t alignment, bool zero, tcache_t *tcache,
|
||||||
size_t oldusize = extent_usize_get(extent);
|
hook_ralloc_args_t *hook_args) {
|
||||||
|
extent_t *extent = iealloc(tsdn, ptr);
|
||||||
|
|
||||||
|
size_t oldusize = extent_usize_get(extent);
|
||||||
/* The following should have been caught by callers. */
|
/* The following should have been caught by callers. */
|
||||||
assert(usize > 0 && usize <= LARGE_MAXCLASS);
|
assert(usize > 0 && usize <= SC_LARGE_MAXCLASS);
|
||||||
/* Both allocation sizes must be large to avoid a move. */
|
/* Both allocation sizes must be large to avoid a move. */
|
||||||
assert(oldusize >= LARGE_MINCLASS && usize >= LARGE_MINCLASS);
|
assert(oldusize >= SC_LARGE_MINCLASS
|
||||||
|
&& usize >= SC_LARGE_MINCLASS);
|
||||||
|
|
||||||
/* Try to avoid moving the allocation. */
|
/* Try to avoid moving the allocation. */
|
||||||
if (!large_ralloc_no_move(tsdn, extent, usize, usize, zero)) {
|
if (!large_ralloc_no_move(tsdn, extent, usize, usize, zero)) {
|
||||||
|
hook_invoke_expand(hook_args->is_realloc
|
||||||
|
? hook_expand_realloc : hook_expand_rallocx, ptr, oldusize,
|
||||||
|
usize, (uintptr_t)ptr, hook_args->args);
|
||||||
return extent_addr_get(extent);
|
return extent_addr_get(extent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,6 +302,12 @@ large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hook_invoke_alloc(hook_args->is_realloc
|
||||||
|
? hook_alloc_realloc : hook_alloc_rallocx, ret, (uintptr_t)ret,
|
||||||
|
hook_args->args);
|
||||||
|
hook_invoke_dalloc(hook_args->is_realloc
|
||||||
|
? hook_dalloc_realloc : hook_dalloc_rallocx, ptr, hook_args->args);
|
||||||
|
|
||||||
size_t copysize = (usize < oldusize) ? usize : oldusize;
|
size_t copysize = (usize < oldusize) ? usize : oldusize;
|
||||||
memcpy(ret, extent_addr_get(extent), copysize);
|
memcpy(ret, extent_addr_get(extent), copysize);
|
||||||
isdalloct(tsdn, extent_addr_get(extent), oldusize, tcache, NULL, true);
|
isdalloct(tsdn, extent_addr_get(extent), oldusize, tcache, NULL, true);
|
||||||
@ -318,8 +331,9 @@ large_dalloc_prep_impl(tsdn_t *tsdn, arena_t *arena, extent_t *extent,
|
|||||||
large_dalloc_maybe_junk(extent_addr_get(extent),
|
large_dalloc_maybe_junk(extent_addr_get(extent),
|
||||||
extent_usize_get(extent));
|
extent_usize_get(extent));
|
||||||
} else {
|
} else {
|
||||||
malloc_mutex_assert_owner(tsdn, &arena->large_mtx);
|
/* Only hold the large_mtx if necessary. */
|
||||||
if (!arena_is_auto(arena)) {
|
if (!arena_is_auto(arena)) {
|
||||||
|
malloc_mutex_assert_owner(tsdn, &arena->large_mtx);
|
||||||
extent_list_remove(&arena->large, extent);
|
extent_list_remove(&arena->large, extent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -369,3 +383,13 @@ void
|
|||||||
large_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent) {
|
large_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent) {
|
||||||
large_prof_tctx_set(tsdn, extent, (prof_tctx_t *)(uintptr_t)1U);
|
large_prof_tctx_set(tsdn, extent, (prof_tctx_t *)(uintptr_t)1U);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nstime_t
|
||||||
|
large_prof_alloc_time_get(const extent_t *extent) {
|
||||||
|
return extent_prof_alloc_time_get(extent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
large_prof_alloc_time_set(extent_t *extent, nstime_t t) {
|
||||||
|
extent_prof_alloc_time_set(extent, t);
|
||||||
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user