From b267d0f86aff15a0edb2929f09060c118ed98ec4 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 13 Aug 2010 15:42:29 -0700 Subject: [PATCH] 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. --- .gitignore | 2 + jemalloc/Makefile.in | 50 +++++++++++++++++++++++- jemalloc/configure.ac | 5 +++ jemalloc/doc/jemalloc.3.in | 13 +++++++ jemalloc/src/ctl.c | 52 +++++++++++++++++++++++++ jemalloc/test/thread_arena.c | 69 ++++++++++++++++++++++++++++++++++ jemalloc/test/thread_arena.exp | 2 + 7 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 jemalloc/test/thread_arena.c create mode 100644 jemalloc/test/thread_arena.exp diff --git a/.gitignore b/.gitignore index d9e49f8f..8e95c7a4 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,6 @@ /jemalloc/src/jemalloc\.h /jemalloc/src/jemalloc_defs\.h /jemalloc/src/*.[od] +/jemalloc/test/*.[od] +/jemalloc/test/*.out /jemalloc/VERSION diff --git a/jemalloc/Makefile.in b/jemalloc/Makefile.in index ac9b7822..a7acc969 100644 --- a/jemalloc/Makefile.in +++ b/jemalloc/Makefile.in @@ -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 diff --git a/jemalloc/configure.ac b/jemalloc/configure.ac index ce6e6799..bf165960 100644 --- a/jemalloc/configure.ac +++ b/jemalloc/configure.ac @@ -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 diff --git a/jemalloc/doc/jemalloc.3.in b/jemalloc/doc/jemalloc.3.in index cf5cb5e0..d2d5b77f 100644 --- a/jemalloc/doc/jemalloc.3.in +++ b/jemalloc/doc/jemalloc.3.in @@ -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. diff --git a/jemalloc/src/ctl.c b/jemalloc/src/ctl.c index ffb732d5..128883f8 100644 --- a/jemalloc/src/ctl.c +++ b/jemalloc/src/ctl.c @@ -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 diff --git a/jemalloc/test/thread_arena.c b/jemalloc/test/thread_arena.c new file mode 100644 index 00000000..99e9669a --- /dev/null +++ b/jemalloc/test/thread_arena.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include + +#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); +} diff --git a/jemalloc/test/thread_arena.exp b/jemalloc/test/thread_arena.exp new file mode 100644 index 00000000..369a88dd --- /dev/null +++ b/jemalloc/test/thread_arena.exp @@ -0,0 +1,2 @@ +Test begin +Test end