Add the thread.arena mallctl.
Make it possible for each thread to manage which arena it is associated with. Implement the 'tests' and 'check' build targets.
This commit is contained in:
parent
dcd15098a8
commit
b267d0f86a
2
.gitignore
vendored
2
.gitignore
vendored
@ -12,4 +12,6 @@
|
|||||||
/jemalloc/src/jemalloc\.h
|
/jemalloc/src/jemalloc\.h
|
||||||
/jemalloc/src/jemalloc_defs\.h
|
/jemalloc/src/jemalloc_defs\.h
|
||||||
/jemalloc/src/*.[od]
|
/jemalloc/src/*.[od]
|
||||||
|
/jemalloc/test/*.[od]
|
||||||
|
/jemalloc/test/*.out
|
||||||
/jemalloc/VERSION
|
/jemalloc/VERSION
|
||||||
|
@ -47,6 +47,10 @@ DSOS := @objroot@lib/libjemalloc@install_suffix@.so.$(REV) \
|
|||||||
@objroot@lib/libjemalloc@install_suffix@.so \
|
@objroot@lib/libjemalloc@install_suffix@.so \
|
||||||
@objroot@lib/libjemalloc@install_suffix@_pic.a
|
@objroot@lib/libjemalloc@install_suffix@_pic.a
|
||||||
MAN3 := @objroot@doc/jemalloc@install_suffix@.3
|
MAN3 := @objroot@doc/jemalloc@install_suffix@.3
|
||||||
|
CTESTS :=
|
||||||
|
ifeq (1, @enable_tls@)
|
||||||
|
CTESTS += @srcroot@test/thread_arena.c
|
||||||
|
endif
|
||||||
|
|
||||||
.PHONY: all dist install check clean distclean relclean
|
.PHONY: all dist install check clean distclean relclean
|
||||||
|
|
||||||
@ -69,12 +73,22 @@ all: $(DSOS)
|
|||||||
|
|
||||||
@objroot@lib/libjemalloc@install_suffix@.so.$(REV) : $(CSRCS:@srcroot@%.c=@objroot@%.o)
|
@objroot@lib/libjemalloc@install_suffix@.so.$(REV) : $(CSRCS:@srcroot@%.c=@objroot@%.o)
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
$(CC) -shared -Wl,-soname,$(@F) -o $@ $+ $(LDFLAGS) $(LIBS)
|
$(CC) -shared -Wl,-soname,$(@F) $(RPATH_EXTRA:%=@RPATH@%) -o $@ $+ $(LDFLAGS) $(LIBS)
|
||||||
|
|
||||||
@objroot@lib/libjemalloc@install_suffix@_pic.a : $(CSRCS:@srcroot@%.c=@objroot@%.o)
|
@objroot@lib/libjemalloc@install_suffix@_pic.a : $(CSRCS:@srcroot@%.c=@objroot@%.o)
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
ar crus $@ $+
|
ar crus $@ $+
|
||||||
|
|
||||||
|
@objroot@test/%.o: @srcroot@test/%.c
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
$(CC) $(CFLAGS) -c $(CPPFLAGS) -o $@ $<
|
||||||
|
@$(SHELL) -ec "$(CC) -MM $(CPPFLAGS) $< | sed \"s/\($(subst /,\/,$(notdir $(basename $@)))\)\.o\([ :]*\)/$(subst /,\/,$(strip $(dir $@)))\1.o \2/g\" > $(@:%.o=%.d)"
|
||||||
|
|
||||||
|
@objroot@test/%: @objroot@test/%.o \
|
||||||
|
@objroot@lib/libjemalloc@install_suffix@.so
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
$(CC) -o $@ $< @RPATH@@objroot@lib -L@objroot@lib -ljemalloc
|
||||||
|
|
||||||
install_bin:
|
install_bin:
|
||||||
install -d $(BINDIR)
|
install -d $(BINDIR)
|
||||||
@for b in $(BINS); do \
|
@for b in $(BINS); do \
|
||||||
@ -104,11 +118,43 @@ done
|
|||||||
|
|
||||||
install: install_bin install_include install_lib install_man
|
install: install_bin install_include install_lib install_man
|
||||||
|
|
||||||
check:
|
tests: $(CTESTS:@srcroot@%.c=@objroot@%)
|
||||||
|
|
||||||
|
check: tests
|
||||||
|
@mkdir -p @objroot@test
|
||||||
|
@$(SHELL) -c 'total=0; \
|
||||||
|
failures=0; \
|
||||||
|
echo "========================================="; \
|
||||||
|
for t in $(CTESTS:@srcroot@%.c=@objroot@%); do \
|
||||||
|
total=`expr $$total + 1`; \
|
||||||
|
/bin/echo -n "$${t} ... "; \
|
||||||
|
$${t} @abs_srcroot@ @abs_objroot@ \
|
||||||
|
> @objroot@$${t}.out 2>&1; \
|
||||||
|
if test -e "@srcroot@$${t}.exp"; then \
|
||||||
|
diff -u @srcroot@$${t}.exp \
|
||||||
|
@objroot@$${t}.out >/dev/null 2>&1; \
|
||||||
|
fail=$$?; \
|
||||||
|
if test "$${fail}" -eq "1" ; then \
|
||||||
|
failures=`expr $${failures} + 1`; \
|
||||||
|
echo "*** FAIL ***"; \
|
||||||
|
else \
|
||||||
|
echo "pass"; \
|
||||||
|
fi; \
|
||||||
|
else \
|
||||||
|
echo "*** FAIL *** (.exp file is missing)"; \
|
||||||
|
failures=`expr $${failures} + 1`; \
|
||||||
|
fi; \
|
||||||
|
done; \
|
||||||
|
echo "========================================="; \
|
||||||
|
echo "Failures: $${failures}/$${total}"'
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(CSRCS:@srcroot@%.c=@objroot@%.o)
|
rm -f $(CSRCS:@srcroot@%.c=@objroot@%.o)
|
||||||
rm -f $(CSRCS:@srcroot@%.c=@objroot@%.d)
|
rm -f $(CSRCS:@srcroot@%.c=@objroot@%.d)
|
||||||
|
rm -f $(CTESTS:@srcroot@%.c=@objroot@%)
|
||||||
|
rm -f $(CTESTS:@srcroot@%.c=@objroot@%.o)
|
||||||
|
rm -f $(CTESTS:@srcroot@%.c=@objroot@%.d)
|
||||||
|
rm -f $(CTESTS:@srcroot@%.c=@objroot@%.out)
|
||||||
rm -f $(DSOS)
|
rm -f $(DSOS)
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
|
@ -647,9 +647,14 @@ AC_RUN_IFELSE([AC_LANG_PROGRAM(
|
|||||||
AC_MSG_RESULT([no])
|
AC_MSG_RESULT([no])
|
||||||
enable_tls="0")
|
enable_tls="0")
|
||||||
fi
|
fi
|
||||||
|
AC_SUBST([enable_tls])
|
||||||
if test "x${enable_tls}" = "x0" ; then
|
if test "x${enable_tls}" = "x0" ; then
|
||||||
AC_DEFINE_UNQUOTED([NO_TLS], [ ])
|
AC_DEFINE_UNQUOTED([NO_TLS], [ ])
|
||||||
|
roff_tls=".\\\" "
|
||||||
|
else
|
||||||
|
roff_tls=""
|
||||||
fi
|
fi
|
||||||
|
AC_SUBST([roff_tls])
|
||||||
|
|
||||||
dnl Finish tcache-related definitions, now that TLS configuration is done.
|
dnl Finish tcache-related definitions, now that TLS configuration is done.
|
||||||
if test "x$enable_tls" = "x0" ; then
|
if test "x$enable_tls" = "x0" ; then
|
||||||
|
@ -669,6 +669,19 @@ This is useful for detecting whether another thread caused a refresh.
|
|||||||
@roff_tcache@find manual flushing useful.
|
@roff_tcache@find manual flushing useful.
|
||||||
.Ed
|
.Ed
|
||||||
.\"-----------------------------------------------------------------------------
|
.\"-----------------------------------------------------------------------------
|
||||||
|
@roff_tls@.It Sy "thread.arena (unsigned) rw"
|
||||||
|
@roff_tls@.Bd -ragged -offset indent -compact
|
||||||
|
@roff_tls@Get or set the arena associated with the calling thread.
|
||||||
|
@roff_tls@The arena index must be less than the maximum number of arenas (see
|
||||||
|
@roff_tls@the
|
||||||
|
@roff_tls@.Dq arenas.narenas
|
||||||
|
@roff_tls@mallctl).
|
||||||
|
@roff_tls@If the specified arena was not initialized beforehand (see the
|
||||||
|
@roff_tls@.Dq arenas.initialized
|
||||||
|
@roff_tls@mallctl), it will be automatically initialized as a side effect of
|
||||||
|
@roff_tls@calling this interface.
|
||||||
|
@roff_tls@.Ed
|
||||||
|
.\"-----------------------------------------------------------------------------
|
||||||
.It Sy "config.debug (bool) r-"
|
.It Sy "config.debug (bool) r-"
|
||||||
.Bd -ragged -offset indent -compact
|
.Bd -ragged -offset indent -compact
|
||||||
--enable-debug was specified during build configuration.
|
--enable-debug was specified during build configuration.
|
||||||
|
@ -41,6 +41,9 @@ CTL_PROTO(epoch)
|
|||||||
#ifdef JEMALLOC_TCACHE
|
#ifdef JEMALLOC_TCACHE
|
||||||
CTL_PROTO(tcache_flush)
|
CTL_PROTO(tcache_flush)
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef NO_TLS
|
||||||
|
CTL_PROTO(thread_arena)
|
||||||
|
#endif
|
||||||
CTL_PROTO(config_debug)
|
CTL_PROTO(config_debug)
|
||||||
CTL_PROTO(config_dss)
|
CTL_PROTO(config_dss)
|
||||||
CTL_PROTO(config_dynamic_page_shift)
|
CTL_PROTO(config_dynamic_page_shift)
|
||||||
@ -210,6 +213,12 @@ static const ctl_node_t tcache_node[] = {
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef NO_TLS
|
||||||
|
static const ctl_node_t thread_node[] = {
|
||||||
|
{NAME("arena"), CTL(thread_arena)}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
static const ctl_node_t config_node[] = {
|
static const ctl_node_t config_node[] = {
|
||||||
{NAME("debug"), CTL(config_debug)},
|
{NAME("debug"), CTL(config_debug)},
|
||||||
{NAME("dss"), CTL(config_dss)},
|
{NAME("dss"), CTL(config_dss)},
|
||||||
@ -447,6 +456,9 @@ static const ctl_node_t root_node[] = {
|
|||||||
{NAME("epoch"), CTL(epoch)},
|
{NAME("epoch"), CTL(epoch)},
|
||||||
#ifdef JEMALLOC_TCACHE
|
#ifdef JEMALLOC_TCACHE
|
||||||
{NAME("tcache"), CHILD(tcache)},
|
{NAME("tcache"), CHILD(tcache)},
|
||||||
|
#endif
|
||||||
|
#ifndef NO_TLS
|
||||||
|
{NAME("thread"), CHILD(thread)},
|
||||||
#endif
|
#endif
|
||||||
{NAME("config"), CHILD(config)},
|
{NAME("config"), CHILD(config)},
|
||||||
{NAME("opt"), CHILD(opt)},
|
{NAME("opt"), CHILD(opt)},
|
||||||
@ -1042,6 +1054,46 @@ RETURN:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef NO_TLS
|
||||||
|
static int
|
||||||
|
thread_arena_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
||||||
|
void *newp, size_t newlen)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
unsigned newind, oldind;
|
||||||
|
|
||||||
|
newind = oldind = choose_arena()->ind;
|
||||||
|
WRITE(oldind, unsigned);
|
||||||
|
READ(newind, unsigned);
|
||||||
|
if (newind != oldind) {
|
||||||
|
arena_t *arena;
|
||||||
|
|
||||||
|
if (newind >= narenas) {
|
||||||
|
/* New arena index is out of range. */
|
||||||
|
ret = EFAULT;
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize arena if necessary. */
|
||||||
|
malloc_mutex_lock(&arenas_lock);
|
||||||
|
if ((arena = arenas[newind]) == NULL)
|
||||||
|
arena = arenas_extend(newind);
|
||||||
|
malloc_mutex_unlock(&arenas_lock);
|
||||||
|
if (arena == NULL) {
|
||||||
|
ret = EAGAIN;
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set new arena association. */
|
||||||
|
arenas_map = arena;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
RETURN:
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
#ifdef JEMALLOC_DEBUG
|
#ifdef JEMALLOC_DEBUG
|
||||||
|
69
jemalloc/test/thread_arena.c
Normal file
69
jemalloc/test/thread_arena.c
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "jemalloc/jemalloc.h"
|
||||||
|
|
||||||
|
void *
|
||||||
|
thread_start(void *arg)
|
||||||
|
{
|
||||||
|
unsigned main_arena_ind = *(unsigned *)arg;
|
||||||
|
unsigned arena_ind;
|
||||||
|
size_t size;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
malloc(1);
|
||||||
|
|
||||||
|
size = sizeof(arena_ind);
|
||||||
|
if ((err = mallctl("thread.arena", &arena_ind, &size,
|
||||||
|
&main_arena_ind, sizeof(main_arena_ind)))) {
|
||||||
|
fprintf(stderr, "%s(): Error in mallctl(): %s\n", __func__,
|
||||||
|
strerror(err));
|
||||||
|
return (void *)1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
unsigned arena_ind;
|
||||||
|
size_t size;
|
||||||
|
int err;
|
||||||
|
pthread_t thread;
|
||||||
|
|
||||||
|
fprintf(stderr, "Test begin\n");
|
||||||
|
|
||||||
|
malloc(1);
|
||||||
|
|
||||||
|
size = sizeof(arena_ind);
|
||||||
|
if ((err = mallctl("thread.arena", &arena_ind, &size, NULL, 0))) {
|
||||||
|
fprintf(stderr, "%s(): Error in mallctl(): %s\n", __func__,
|
||||||
|
strerror(err));
|
||||||
|
ret = 1;
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pthread_create(&thread, NULL, thread_start, (void *)&arena_ind)
|
||||||
|
!= 0) {
|
||||||
|
fprintf(stderr, "%s(): Error in pthread_create()\n", __func__);
|
||||||
|
ret = 1;
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
|
pthread_join(thread, (void *)&ret);
|
||||||
|
|
||||||
|
if (pthread_create(&thread, NULL, thread_start, (void *)&arena_ind)
|
||||||
|
!= 0) {
|
||||||
|
fprintf(stderr, "%s(): Error in pthread_create()\n", __func__);
|
||||||
|
ret = 1;
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
|
pthread_join(thread, (void *)&ret);
|
||||||
|
|
||||||
|
RETURN:
|
||||||
|
fprintf(stderr, "Test end\n");
|
||||||
|
return (ret);
|
||||||
|
}
|
2
jemalloc/test/thread_arena.exp
Normal file
2
jemalloc/test/thread_arena.exp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
Test begin
|
||||||
|
Test end
|
Loading…
Reference in New Issue
Block a user