[master] e241de0 umem: default options, warn about umem loaded, lazy loading

Nils Goroll nils.goroll at uplex.de
Wed Apr 4 14:49:11 UTC 2018


commit e241de074fd3b47437bba0ddb8449fb755102f51
Author: Nils Goroll <nils.goroll at uplex.de>
Date:   Wed Apr 4 16:13:14 2018 +0200

    umem: default options, warn about umem loaded, lazy loading
    
    default options:
    
    For co-existance with libc malloc and potentially other allocators, we
    should use mmap() regions in favor of sbrk(). Also, libumem's perthread
    cache only makes sense when umem is actually used for all allocations
    and, by default, requires an additional massive 1MB per thread, which
    is totally out of scale with how we manage memory in varnish.
    
    if libumem is found to already be loaded, we cannot set its options,
    so warn about that fact.
    
    As we only use function pointers to libumem, lazy loading of symbols
    should be the better option.

diff --git a/bin/varnishd/storage/storage_umem.c b/bin/varnishd/storage/storage_umem.c
index 7464a19..5471331 100644
--- a/bin/varnishd/storage/storage_umem.c
+++ b/bin/varnishd/storage/storage_umem.c
@@ -42,6 +42,7 @@
 #include <umem.h>
 #include <dlfcn.h>
 #include <link.h>
+#include <string.h>
 
 #include "storage/storage.h"
 #include "storage/storage_simple.h"
@@ -93,6 +94,9 @@ static umem_cache_destroy_f umem_cache_destroyf = NULL;
 static umem_cache_alloc_f umem_cache_allocf = NULL;
 static umem_cache_free_f umem_cache_freef = NULL;
 
+static const char * const def_umem_options = "perthread_cache=0,backend=mmap";
+static const char * const env_umem_options = "UMEM_OPTIONS";
+
 /* init required per cache get:
    smu->sz = size
    smu->s.ptr;
@@ -241,8 +245,46 @@ smu_free_space(const struct stevedore *st)
 }
 
 static void
+smu_umem_loaded_warn(void)
+{
+	const char *e;
+	static int warned = 0;
+
+	if (warned++)
+		return;
+
+	fprintf(stderr, "notice:\tlibumem was already found to be loaded\n"
+		"\tand will likely be used for all allocations\n");
+
+	e = getenv(env_umem_options);
+	if (e == NULL || ! strstr(e, def_umem_options))
+		fprintf(stderr, "\tit is recommended to set %s=%s "
+			"before starting varnish\n",
+			env_umem_options, def_umem_options);
+}
+
+static int
+smu_umem_loaded(void)
+{
+	void *h = NULL;
+
+	h = dlopen("libumem.so", RTLD_NOLOAD);
+	if (h) {
+		AZ(dlclose(h));
+		return (1);
+	}
+
+	h = dlsym(RTLD_DEFAULT, "umem_alloc");
+	if (h)
+		return (1);
+
+	return (0);
+}
+
+static void
 smu_init(struct stevedore *parent, int ac, char * const *av)
 {
+	static int inited = 0;
 	const char *e;
 	uintmax_t u;
 	struct smu_sc *sc;
@@ -258,8 +300,25 @@ smu_init(struct stevedore *parent, int ac, char * const *av)
 	if (ac > 1)
 		ARGV_ERR("(-sumem) too many arguments\n");
 
-	if (ac == 0 || *av[0] == '\0')
-		 return;
+	if (ac == 1 && *av[0] != '\0') {
+		e = VNUM_2bytes(av[0], &u, 0);
+		if (e != NULL)
+			ARGV_ERR("(-sumem) size \"%s\": %s\n", av[0], e);
+		if ((u != (uintmax_t)(size_t)u))
+			ARGV_ERR("(-sumem) size \"%s\": too big\n", av[0]);
+		if (u < 1024*1024)
+			ARGV_ERR("(-sumem) size \"%s\": too smull, "
+				 "did you forget to specify M or G?\n", av[0]);
+		sc->smu_max = u;
+	}
+
+	if (inited++)
+		return;
+
+	if (smu_umem_loaded())
+		smu_umem_loaded_warn();
+	else
+		AZ(setenv(env_umem_options, def_umem_options, 0));
 
 	/* Check if these load in the management process. */
 	(void) dlerror();
@@ -286,17 +345,45 @@ smu_init(struct stevedore *parent, int ac, char * const *av)
 
 	AZ(dlclose(libumem_hndl));
 	libumem_hndl = NULL;
+}
+
+/*
+ * Load the symbols for use in the child process, assert if they fail to load.
+ */
+static void
+smu_open_init(void)
+{
+	static int inited = 0;
+
+	if (inited++) {
+		AN(libumem_hndl);
+		AN(umem_allocf);
+		return;
+	}
+
+	if (smu_umem_loaded())
+		smu_umem_loaded_warn();
+	else
+		AN(getenv(env_umem_options));
+
+	AZ(libumem_hndl);
+	libumem_hndl = dlopen("libumem.so", RTLD_LAZY);
+	AN(libumem_hndl);
 
-	e = VNUM_2bytes(av[0], &u, 0);
-	if (e != NULL)
-		ARGV_ERR("(-sumem) size \"%s\": %s\n", av[0], e);
-	if ((u != (uintmax_t)(size_t)u))
-		ARGV_ERR("(-sumem) size \"%s\": too big\n", av[0]);
-	if (u < 1024*1024)
-		ARGV_ERR("(-sumem) size \"%s\": too smull, "
-			 "did you forget to specify M or G?\n", av[0]);
+#define DLSYM_UMEM(fptr,sym)					\
+	do {							\
+		fptr = dlsym(libumem_hndl, #sym);		\
+		AN(fptr);					\
+	} while(0)
 
-	sc->smu_max = u;
+	DLSYM_UMEM(umem_allocf, umem_alloc);
+	DLSYM_UMEM(umem_freef, umem_free);
+	DLSYM_UMEM(umem_cache_createf, umem_cache_create);
+	DLSYM_UMEM(umem_cache_destroyf, umem_cache_destroy);
+	DLSYM_UMEM(umem_cache_allocf, umem_cache_alloc);
+	DLSYM_UMEM(umem_cache_freef, umem_cache_free);
+
+#undef DLSYM_UMEM
 }
 
 static void v_matchproto_(storage_open_f)
@@ -314,30 +401,7 @@ smu_open(struct stevedore *st)
 	if (smu_sc->smu_max != SIZE_MAX)
 		smu_sc->stats->g_space = smu_sc->smu_max;
 
-	/*
-	 * Load the symbols for use in the child process, assert if they
-	 * fail to load.
-	 */
-	if (libumem_hndl == NULL) {
-		libumem_hndl = dlopen("libumem.so", RTLD_NOW);
-		AN(libumem_hndl);
-
-#define DLSYM_UMEM(fptr,sym)					\
-		do {						\
-			fptr = dlsym(libumem_hndl, #sym);	\
-			AN(fptr);				\
-		} while(0)
-
-	DLSYM_UMEM(umem_allocf, umem_alloc);
-	DLSYM_UMEM(umem_freef, umem_free);
-	DLSYM_UMEM(umem_cache_createf, umem_cache_create);
-	DLSYM_UMEM(umem_cache_destroyf, umem_cache_destroy);
-	DLSYM_UMEM(umem_cache_allocf, umem_cache_alloc);
-	DLSYM_UMEM(umem_cache_freef, umem_cache_free);
-
-#undef DLSYM_UMEM
-
-	}
+	smu_open_init();
 
 	smu_sc->smu_cache = umem_cache_createf(st->ident,
 					  sizeof(struct smu),


More information about the varnish-commit mailing list