mirror of
https://github.com/jemalloc/jemalloc.git
synced 2026-07-22 04:03:11 +00:00
Compare commits
2 Commits
8361239b03
...
b44e84086f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b44e84086f | ||
|
|
68c35f6557 |
@@ -276,6 +276,7 @@ TESTS_UNIT := \
|
|||||||
$(srcroot)test/unit/pack.c \
|
$(srcroot)test/unit/pack.c \
|
||||||
$(srcroot)test/unit/pages.c \
|
$(srcroot)test/unit/pages.c \
|
||||||
$(srcroot)test/unit/peak.c \
|
$(srcroot)test/unit/peak.c \
|
||||||
|
$(srcroot)test/unit/percpu_arena_resume.c \
|
||||||
$(srcroot)test/unit/ph.c \
|
$(srcroot)test/unit/ph.c \
|
||||||
$(srcroot)test/unit/prng.c \
|
$(srcroot)test/unit/prng.c \
|
||||||
$(srcroot)test/unit/prof_accum.c \
|
$(srcroot)test/unit/prof_accum.c \
|
||||||
|
|||||||
56
configure.ac
56
configure.ac
@@ -533,13 +533,14 @@ esac
|
|||||||
AC_DEFINE_UNQUOTED([HAVE_CPU_SPINWAIT], [$HAVE_CPU_SPINWAIT], [ ])
|
AC_DEFINE_UNQUOTED([HAVE_CPU_SPINWAIT], [$HAVE_CPU_SPINWAIT], [ ])
|
||||||
AC_DEFINE_UNQUOTED([CPU_SPINWAIT], [$CPU_SPINWAIT], [ ])
|
AC_DEFINE_UNQUOTED([CPU_SPINWAIT], [$CPU_SPINWAIT], [ ])
|
||||||
|
|
||||||
|
dnl LG_VADDR: number of significant virtual address bits. Auto-detected when --with-lg-vaddr is left unset.
|
||||||
AC_ARG_WITH([lg_vaddr],
|
AC_ARG_WITH([lg_vaddr],
|
||||||
[AS_HELP_STRING([--with-lg-vaddr=<lg-vaddr>], [Number of significant virtual address bits])],
|
[AS_HELP_STRING([--with-lg-vaddr=<lg-vaddr>], [Number of significant virtual address bits])],
|
||||||
[LG_VADDR="$with_lg_vaddr"], [LG_VADDR="detect"])
|
[LG_VADDR="$with_lg_vaddr"], [LG_VADDR="detect"])
|
||||||
|
|
||||||
case "${host_cpu}" in
|
if test "x$LG_VADDR" = "xdetect"; then
|
||||||
aarch64)
|
case "${host_cpu}" in
|
||||||
if test "x$LG_VADDR" = "xdetect"; then
|
aarch64)
|
||||||
AC_MSG_CHECKING([number of significant virtual address bits])
|
AC_MSG_CHECKING([number of significant virtual address bits])
|
||||||
if test "x${LG_SIZEOF_PTR}" = "x2" ; then
|
if test "x${LG_SIZEOF_PTR}" = "x2" ; then
|
||||||
#aarch64 ILP32
|
#aarch64 ILP32
|
||||||
@@ -549,10 +550,8 @@ case "${host_cpu}" in
|
|||||||
LG_VADDR=48
|
LG_VADDR=48
|
||||||
fi
|
fi
|
||||||
AC_MSG_RESULT([$LG_VADDR])
|
AC_MSG_RESULT([$LG_VADDR])
|
||||||
fi
|
;;
|
||||||
;;
|
x86_64)
|
||||||
x86_64)
|
|
||||||
if test "x$LG_VADDR" = "xdetect"; then
|
|
||||||
AC_CACHE_CHECK([number of significant virtual address bits],
|
AC_CACHE_CHECK([number of significant virtual address bits],
|
||||||
[je_cv_lg_vaddr],
|
[je_cv_lg_vaddr],
|
||||||
AC_RUN_IFELSE([AC_LANG_PROGRAM(
|
AC_RUN_IFELSE([AC_LANG_PROGRAM(
|
||||||
@@ -592,15 +591,33 @@ typedef unsigned __int32 uint32_t;
|
|||||||
[je_cv_lg_vaddr=`cat conftest.out`],
|
[je_cv_lg_vaddr=`cat conftest.out`],
|
||||||
[je_cv_lg_vaddr=error],
|
[je_cv_lg_vaddr=error],
|
||||||
[je_cv_lg_vaddr=57]))
|
[je_cv_lg_vaddr=57]))
|
||||||
|
if test "x${je_cv_lg_vaddr}" = "xerror" ; then
|
||||||
|
AC_MSG_ERROR([cannot determine number of significant virtual address bits])
|
||||||
|
fi
|
||||||
if test "x${je_cv_lg_vaddr}" != "x" ; then
|
if test "x${je_cv_lg_vaddr}" != "x" ; then
|
||||||
LG_VADDR="${je_cv_lg_vaddr}"
|
LG_VADDR="${je_cv_lg_vaddr}"
|
||||||
fi
|
fi
|
||||||
if test "x${LG_VADDR}" != "xerror" ; then
|
;;
|
||||||
AC_DEFINE_UNQUOTED([LG_VADDR], [$LG_VADDR], [ ])
|
*)
|
||||||
|
AC_MSG_CHECKING([number of significant virtual address bits])
|
||||||
|
if test "x${LG_SIZEOF_PTR}" = "x3" ; then
|
||||||
|
LG_VADDR=64
|
||||||
|
elif test "x${LG_SIZEOF_PTR}" = "x2" ; then
|
||||||
|
LG_VADDR=32
|
||||||
|
elif test "x${LG_SIZEOF_PTR}" = "xLG_SIZEOF_PTR_WIN" ; then
|
||||||
|
LG_VADDR="(1U << (LG_SIZEOF_PTR_WIN+3))"
|
||||||
else
|
else
|
||||||
AC_MSG_ERROR([cannot determine number of significant virtual address bits])
|
AC_MSG_ERROR([Unsupported lg(pointer size): ${LG_SIZEOF_PTR}])
|
||||||
fi
|
fi
|
||||||
fi
|
AC_MSG_RESULT([$LG_VADDR])
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
AC_DEFINE_UNQUOTED([LG_VADDR], [$LG_VADDR], [ ])
|
||||||
|
|
||||||
|
dnl rdtscp feature probe for x86_64
|
||||||
|
case "${host_cpu}" in
|
||||||
|
x86_64)
|
||||||
AC_CACHE_CHECK([rdtscp support],
|
AC_CACHE_CHECK([rdtscp support],
|
||||||
[je_cv_rdtscp],
|
[je_cv_rdtscp],
|
||||||
AC_RUN_IFELSE([AC_LANG_PROGRAM(
|
AC_RUN_IFELSE([AC_LANG_PROGRAM(
|
||||||
@@ -619,23 +636,8 @@ typedef unsigned __int32 uint32_t;
|
|||||||
AC_DEFINE([JEMALLOC_HAVE_RDTSCP], [ ], [ ])
|
AC_DEFINE([JEMALLOC_HAVE_RDTSCP], [ ], [ ])
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
*)
|
|
||||||
if test "x$LG_VADDR" = "xdetect"; then
|
|
||||||
AC_MSG_CHECKING([number of significant virtual address bits])
|
|
||||||
if test "x${LG_SIZEOF_PTR}" = "x3" ; then
|
|
||||||
LG_VADDR=64
|
|
||||||
elif test "x${LG_SIZEOF_PTR}" = "x2" ; then
|
|
||||||
LG_VADDR=32
|
|
||||||
elif test "x${LG_SIZEOF_PTR}" = "xLG_SIZEOF_PTR_WIN" ; then
|
|
||||||
LG_VADDR="(1U << (LG_SIZEOF_PTR_WIN+3))"
|
|
||||||
else
|
|
||||||
AC_MSG_ERROR([Unsupported lg(pointer size): ${LG_SIZEOF_PTR}])
|
|
||||||
fi
|
|
||||||
AC_MSG_RESULT([$LG_VADDR])
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
AC_DEFINE_UNQUOTED([LG_VADDR], [$LG_VADDR], [ ])
|
|
||||||
AC_CACHE_CHECK([asm volatile support],
|
AC_CACHE_CHECK([asm volatile support],
|
||||||
[je_cv_asm_volatile],
|
[je_cv_asm_volatile],
|
||||||
AC_RUN_IFELSE([AC_LANG_PROGRAM(
|
AC_RUN_IFELSE([AC_LANG_PROGRAM(
|
||||||
|
|||||||
14
src/ctl.c
14
src/ctl.c
@@ -2374,10 +2374,18 @@ thread_arena_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
|
|||||||
if (have_percpu_arena && PERCPU_ARENA_ENABLED(opt_percpu_arena)) {
|
if (have_percpu_arena && PERCPU_ARENA_ENABLED(opt_percpu_arena)) {
|
||||||
if (newind < percpu_arena_ind_limit(opt_percpu_arena)) {
|
if (newind < percpu_arena_ind_limit(opt_percpu_arena)) {
|
||||||
/*
|
/*
|
||||||
* If perCPU arena is enabled, thread_arena control is
|
* Setting thread.arena to an arena in the auto range
|
||||||
* not allowed for the auto arena range.
|
* means "resume automatic per-CPU selection" rather than
|
||||||
|
* pinning to a specific per-CPU arena. This lets a caller
|
||||||
|
* that temporarily switched to a manually managed arena
|
||||||
|
* (e.g. a scoped guard) hand the thread back to per-CPU
|
||||||
|
* management. It is otherwise impossible: a thread bound
|
||||||
|
* to a manual arena is never reclaimed by percpu (see
|
||||||
|
* arena_choose_impl), so without this it would stay
|
||||||
|
* pinned forever.
|
||||||
*/
|
*/
|
||||||
return EPERM;
|
percpu_arena_update(tsd, percpu_arena_choose());
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -764,12 +764,17 @@ TEST_BEGIN(test_thread_arena) {
|
|||||||
0, "Unexpected mallctl() failure");
|
0, "Unexpected mallctl() failure");
|
||||||
new_arena_ind = percpu_arena_ind_limit(opt_percpu_arena) - 1;
|
new_arena_ind = percpu_arena_ind_limit(opt_percpu_arena) - 1;
|
||||||
if (old_arena_ind != new_arena_ind) {
|
if (old_arena_ind != new_arena_ind) {
|
||||||
|
/*
|
||||||
|
* Setting thread.arena to an index within the per-CPU
|
||||||
|
* range resumes automatic per-CPU selection rather than
|
||||||
|
* failing (see test/unit/percpu_arena_resume.c).
|
||||||
|
*/
|
||||||
expect_d_eq(
|
expect_d_eq(
|
||||||
mallctl("thread.arena", (void *)&old_arena_ind, &sz,
|
mallctl("thread.arena", (void *)&old_arena_ind, &sz,
|
||||||
(void *)&new_arena_ind, sizeof(unsigned)),
|
(void *)&new_arena_ind, sizeof(unsigned)),
|
||||||
EPERM,
|
0,
|
||||||
"thread.arena ctl "
|
"thread.arena within the per-CPU range should "
|
||||||
"should not be allowed with percpu arena");
|
"resume per-CPU selection");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
81
test/unit/percpu_arena_resume.c
Normal file
81
test/unit/percpu_arena_resume.c
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
#include "test/jemalloc_test.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Under percpu_arena, binding a thread to a manual arena (an index at or above
|
||||||
|
* the per-CPU auto range) is one-way: percpu never reclaims it (see
|
||||||
|
* arena_choose_impl). Setting thread.arena back to an index in the auto range
|
||||||
|
* resumes per-CPU selection instead of failing with EPERM.
|
||||||
|
*/
|
||||||
|
TEST_BEGIN(test_thread_arena_resume_percpu) {
|
||||||
|
test_skip_if(!have_percpu_arena
|
||||||
|
|| !PERCPU_ARENA_ENABLED(opt_percpu_arena));
|
||||||
|
|
||||||
|
unsigned limit = percpu_arena_ind_limit(opt_percpu_arena);
|
||||||
|
/* Bypass the tcache so every allocation and free hits the arena. */
|
||||||
|
const int flags = MALLOCX_TCACHE_NONE;
|
||||||
|
|
||||||
|
void *warm = mallocx(1, 0);
|
||||||
|
expect_ptr_not_null(warm, "Unexpected mallocx() failure");
|
||||||
|
dallocx(warm, 0);
|
||||||
|
|
||||||
|
unsigned cur;
|
||||||
|
size_t sz = sizeof(cur);
|
||||||
|
expect_d_eq(mallctl("thread.arena", (void *)&cur, &sz, NULL, 0), 0,
|
||||||
|
"Unexpected mallctl() failure");
|
||||||
|
expect_u_lt(cur, limit, "Thread should start on a per-CPU arena");
|
||||||
|
|
||||||
|
unsigned manual;
|
||||||
|
sz = sizeof(manual);
|
||||||
|
expect_d_eq(mallctl("arenas.create", (void *)&manual, &sz, NULL, 0), 0,
|
||||||
|
"Unexpected arenas.create() failure");
|
||||||
|
expect_u_ge(manual, limit, "A manual arena is outside the per-CPU range");
|
||||||
|
|
||||||
|
unsigned old;
|
||||||
|
sz = sizeof(old);
|
||||||
|
expect_d_eq(mallctl("thread.arena", (void *)&old, &sz, (void *)&manual,
|
||||||
|
sizeof(manual)), 0, "Binding to a manual arena should be allowed");
|
||||||
|
sz = sizeof(cur);
|
||||||
|
expect_d_eq(mallctl("thread.arena", (void *)&cur, &sz, NULL, 0), 0,
|
||||||
|
"Unexpected mallctl() failure");
|
||||||
|
expect_u_eq(cur, manual, "Thread should be bound to the manual arena");
|
||||||
|
|
||||||
|
void *p_manual = mallocx(1024, flags);
|
||||||
|
expect_ptr_not_null(p_manual, "Unexpected mallocx() failure");
|
||||||
|
unsigned found;
|
||||||
|
sz = sizeof(found);
|
||||||
|
expect_d_eq(mallctl("arenas.lookup", (void *)&found, &sz,
|
||||||
|
(void *)&p_manual, sizeof(p_manual)), 0,
|
||||||
|
"Unexpected arenas.lookup() failure");
|
||||||
|
expect_u_eq(found, manual, "Allocation should come from the manual arena");
|
||||||
|
|
||||||
|
void *scratch = mallocx(1024, flags);
|
||||||
|
expect_ptr_not_null(scratch, "Unexpected mallocx() failure");
|
||||||
|
dallocx(scratch, flags);
|
||||||
|
|
||||||
|
unsigned resume = 0;
|
||||||
|
expect_d_eq(mallctl("thread.arena", NULL, NULL, (void *)&resume,
|
||||||
|
sizeof(resume)), 0, "Should resume per-CPU selection, not fail");
|
||||||
|
sz = sizeof(cur);
|
||||||
|
expect_d_eq(mallctl("thread.arena", (void *)&cur, &sz, NULL, 0), 0,
|
||||||
|
"Unexpected mallctl() failure");
|
||||||
|
expect_u_lt(cur, limit, "Thread should be back on a per-CPU arena");
|
||||||
|
|
||||||
|
void *p_percpu = mallocx(1024, flags);
|
||||||
|
expect_ptr_not_null(p_percpu, "Unexpected mallocx() failure");
|
||||||
|
sz = sizeof(found);
|
||||||
|
expect_d_eq(mallctl("arenas.lookup", (void *)&found, &sz,
|
||||||
|
(void *)&p_percpu, sizeof(p_percpu)), 0,
|
||||||
|
"Unexpected arenas.lookup() failure");
|
||||||
|
expect_u_lt(found, limit, "Allocation should come from a per-CPU arena");
|
||||||
|
dallocx(p_percpu, flags);
|
||||||
|
|
||||||
|
/* Free the manual-arena region while bound to a different arena. */
|
||||||
|
dallocx(p_manual, flags);
|
||||||
|
}
|
||||||
|
TEST_END
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void) {
|
||||||
|
return test(
|
||||||
|
test_thread_arena_resume_percpu);
|
||||||
|
}
|
||||||
3
test/unit/percpu_arena_resume.sh
Normal file
3
test/unit/percpu_arena_resume.sh
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
export MALLOC_CONF="percpu_arena:percpu"
|
||||||
Reference in New Issue
Block a user