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:
Jason Evans 2010-08-13 15:42:29 -07:00
parent dcd15098a8
commit b267d0f86a
7 changed files with 191 additions and 2 deletions

2
.gitignore vendored
View File

@ -12,4 +12,6 @@
/jemalloc/src/jemalloc\.h
/jemalloc/src/jemalloc_defs\.h
/jemalloc/src/*.[od]
/jemalloc/test/*.[od]
/jemalloc/test/*.out
/jemalloc/VERSION

View File

@ -47,6 +47,10 @@ DSOS := @objroot@lib/libjemalloc@install_suffix@.so.$(REV) \
@objroot@lib/libjemalloc@install_suffix@.so \
@objroot@lib/libjemalloc@install_suffix@_pic.a
MAN3 := @objroot@doc/jemalloc@install_suffix@.3
CTESTS :=
ifeq (1, @enable_tls@)
CTESTS += @srcroot@test/thread_arena.c
endif
.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)
@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)
@mkdir -p $(@D)
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 -d $(BINDIR)
@for b in $(BINS); do \
@ -104,11 +118,43 @@ done
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:
rm -f $(CSRCS:@srcroot@%.c=@objroot@%.o)
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)
distclean: clean

View File

@ -647,9 +647,14 @@ AC_RUN_IFELSE([AC_LANG_PROGRAM(
AC_MSG_RESULT([no])
enable_tls="0")
fi
AC_SUBST([enable_tls])
if test "x${enable_tls}" = "x0" ; then
AC_DEFINE_UNQUOTED([NO_TLS], [ ])
roff_tls=".\\\" "
else
roff_tls=""
fi
AC_SUBST([roff_tls])
dnl Finish tcache-related definitions, now that TLS configuration is done.
if test "x$enable_tls" = "x0" ; then

View File

@ -669,6 +669,19 @@ This is useful for detecting whether another thread caused a refresh.
@roff_tcache@find manual flushing useful.
.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-"
.Bd -ragged -offset indent -compact
--enable-debug was specified during build configuration.

View File

@ -41,6 +41,9 @@ CTL_PROTO(epoch)
#ifdef JEMALLOC_TCACHE
CTL_PROTO(tcache_flush)
#endif
#ifndef NO_TLS
CTL_PROTO(thread_arena)
#endif
CTL_PROTO(config_debug)
CTL_PROTO(config_dss)
CTL_PROTO(config_dynamic_page_shift)
@ -210,6 +213,12 @@ static const ctl_node_t tcache_node[] = {
};
#endif
#ifndef NO_TLS
static const ctl_node_t thread_node[] = {
{NAME("arena"), CTL(thread_arena)}
};
#endif
static const ctl_node_t config_node[] = {
{NAME("debug"), CTL(config_debug)},
{NAME("dss"), CTL(config_dss)},
@ -447,6 +456,9 @@ static const ctl_node_t root_node[] = {
{NAME("epoch"), CTL(epoch)},
#ifdef JEMALLOC_TCACHE
{NAME("tcache"), CHILD(tcache)},
#endif
#ifndef NO_TLS
{NAME("thread"), CHILD(thread)},
#endif
{NAME("config"), CHILD(config)},
{NAME("opt"), CHILD(opt)},
@ -1042,6 +1054,46 @@ RETURN:
}
#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

View 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);
}

View File

@ -0,0 +1,2 @@
Test begin
Test end