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_defs\.h
|
||||
/jemalloc/src/*.[od]
|
||||
/jemalloc/test/*.[od]
|
||||
/jemalloc/test/*.out
|
||||
/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@_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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
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