From e20cc41e56905fbd32c7824f7cf8bdf6a5db6d1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Tue, 25 May 2021 12:46:00 +0200 Subject: [PATCH] Use system allocator when jemalloc is unavailable This commit adds support for systems where the jemalloc library is not available as a package, here's the quick summary: * On Linux - the jemalloc is usually available as a package, if configured --without-jemalloc, the shim would be used around malloc(), free(), realloc() and malloc_usable_size() * On macOS - the jemalloc is available from homebrew or macports, if configured --without-jemalloc, the shim would be used around malloc(), free(), realloc() and malloc_size() * On FreeBSD - the jemalloc is *the* system allocator, we just need to check for header to get access to non-standard API * On NetBSD - the jemalloc is *the* system allocator, we just need to check for header to get access to non-standard API * On a system hostile to users and developers (read OpenBSD) - the jemalloc API is emulated by using ((size_t *)ptr)[-1] field to hold the size information. The OpenBSD developers care only for themselves, so why should we care about speed on OpenBSD? --- configure.ac | 38 ++++++++++--- lib/isc/Makefile.am | 1 + lib/isc/jemalloc_shim.h | 118 ++++++++++++++++++++++++++++++++++++++++ lib/isc/mem.c | 11 ++++ m4/ax_jemalloc.m4 | 53 ++++++++++++++++++ util/copyrights | 1 + 6 files changed, 214 insertions(+), 8 deletions(-) create mode 100644 lib/isc/jemalloc_shim.h create mode 100644 m4/ax_jemalloc.m4 diff --git a/configure.ac b/configure.ac index 7ada1b61ee..3aa9cc57cb 100644 --- a/configure.ac +++ b/configure.ac @@ -1377,15 +1377,26 @@ AC_SUBST([CMOCKA_LIBS]) AM_CONDITIONAL([HAVE_CMOCKA], [test "$with_cmocka" = "yes"]) # +# Compile with jemalloc (either provided as package or wired in the system on FreeBSD and NetBSD) # -# -AC_MSG_CHECKING([for jemalloc]) -PKG_CHECK_MODULES([JEMALLOC], [jemalloc >= 5], [] - [AC_MSG_WARN([Using jemalloc 5 is recommended]) - PKG_CHECK_MODULES([JEMALLOC], [jemalloc], [], - [AC_MSG_ERROR([jemalloc not found])])]) -AC_SUBST([JEMALLOC_CFLAGS]) -AC_SUBST([JEMALLOC_LIBS]) +# [pairwise: --with-jemalloc=detect, --with-jemalloc=yes, --without-jemalloc] +AC_ARG_WITH([jemalloc], + [AS_HELP_STRING([--with-jemalloc=detect],[enable jemalloc memory allocator (default is detect)])], + [],[with_jemalloc=detect]) + +AS_CASE([$with_jemalloc], + [no],[], + [yes],[AX_CHECK_JEMALLOC( + [AC_DEFINE([HAVE_JEMALLOC], [1], [Define to 1 if jemalloc is available])], + [AC_MSG_ERROR([jemalloc not found])])], + [AX_CHECK_JEMALLOC( + [AC_DEFINE([HAVE_JEMALLOC], [1], [Define to 1 if jemalloc is available]) + with_jemalloc=yes], + [AC_MSG_WARN([jemalloc not found; performance will be reduced]) + with_jemalloc=no])]) + +AS_IF([test "$with_jemalloc" = "no"], + [AC_CHECK_FUNCS([malloc_size malloc_usable_size])]) # # was --with-tuning specified? @@ -1698,6 +1709,9 @@ report() { echo "Configuration summary:" echo "-------------------------------------------------------------------------------" echo "Optional features enabled:" + if test "yes" = "$with_jemalloc"; then + echo " Memory allocator: jemalloc" + fi if test "yes" = "$enable_full_report" -o "standard" = "$with_locktype"; then echo " Mutex lock type: $with_locktype" fi @@ -1754,6 +1768,14 @@ report() { echo "-------------------------------------------------------------------------------" echo "Features disabled or unavailable on this platform:" + if test "no" = "$with_jemalloc"; then + echo " Memory allocator: system" + echo " WARNING: This is not a recommended configuration" + echo " WARNING: Using system memory allocator causes" + echo " WARNING: reduced performance and increased memory" + echo " WARNING: fragmentation. Installing jemalloc >= 4.0.0" + echo " WARNING: memory allocator is strongly recommended." + fi test "small" = "$with_tuning" || echo " Small-system tuning (--with-tuning)" test "no" = "$enable_dnstap" && \ diff --git a/lib/isc/Makefile.am b/lib/isc/Makefile.am index 1b5898817b..5f90634b3a 100644 --- a/lib/isc/Makefile.am +++ b/lib/isc/Makefile.am @@ -167,6 +167,7 @@ libisc_la_SOURCES = \ httpd.c \ interfaceiter.c \ iterated_hash.c \ + jemalloc_shim.h \ lex.c \ lib.c \ log.c \ diff --git a/lib/isc/jemalloc_shim.h b/lib/isc/jemalloc_shim.h new file mode 100644 index 0000000000..11f8099661 --- /dev/null +++ b/lib/isc/jemalloc_shim.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#pragma once + +#if !defined(HAVE_JEMALLOC) + +#include + +const char *malloc_conf = NULL; + +#if defined(HAVE_MALLOC_SIZE) || defined(HAVE_MALLOC_USABLE_SIZE) + +#include + +static inline void * +mallocx(size_t size, int flags) { + UNUSED(flags); + void *__ptr = malloc(size); + REQUIRE(__ptr != NULL); + return (__ptr); +} + +static inline void +sdallocx(void *ptr, size_t size, int flags) { + UNUSED(size); + UNUSED(flags); + + free(ptr); +} + +static inline void * +rallocx(void *ptr, size_t size, int flags) { + UNUSED(flags); + REQUIRE(size != 0); + + void *__ptr = realloc(ptr, size); + REQUIRE(__ptr != NULL); + + return (__ptr); +} + +#ifdef HAVE_MALLOC_SIZE + +#include + +static inline size_t +sallocx(void *ptr, int flags) { + UNUSED(flags); + + return (malloc_size(ptr)); +} + +#elif HAVE_MALLOC_USABLE_SIZE + +#include + +static inline size_t +sallocx(void *ptr, int flags) { + UNUSED(flags); + + return (malloc_usable_size(ptr)); +} + +#endif /* HAVE_MALLOC_SIZE */ + +#else /* defined(HAVE_MALLOC_SIZE) || defined (HAVE_MALLOC_USABLE_SIZE) */ + +#include + +static inline void * +mallocx(size_t size, int flags) { + UNUSED(flags); + + size_t *__ptr = malloc(size + sizeof(size_t)); + REQUIRE(__ptr != NULL); + __ptr[0] = size; + + return (&__ptr[1]); +} + +static inline void +sdallocx(void *ptr, size_t size, int flags) { + UNUSED(size); + UNUSED(flags); + + free(&((size_t *)ptr)[-1]); +} + +static inline size_t +sallocx(void *ptr, int flags) { + UNUSED(flags); + + return (((size_t *)ptr)[-1]); +} + +static inline void * +rallocx(void *ptr, size_t size, int flags) { + UNUSED(flags); + + size_t *__ptr = realloc(&((size_t *)ptr)[-1], size); + REQUIRE(__ptr != NULL); + __ptr[0] = size; + + return (&__ptr[1]); +} + +#endif /* defined(HAVE_MALLOC_SIZE) || defined (HAVE_MALLOC_USABLE_SIZE) */ + +#endif /* !defined(HAVE_JEMALLOC) */ diff --git a/lib/isc/mem.c b/lib/isc/mem.c index ed30d1aa2b..f023737098 100644 --- a/lib/isc/mem.c +++ b/lib/isc/mem.c @@ -42,8 +42,19 @@ #include #endif /* HAVE_JSON_C */ +#if defined(HAVE_MALLOC_NP_H) +#include +#elif defined(HAVE_JEMALLOC) #include +#if JEMALLOC_VERSION_MAJOR < 4 +#define sdallocx(ptr, size, flags) dallocx(ptr, flags) +#endif /* JEMALLOC_VERSION_MAJOR < 4 */ + +#else +#include "jemalloc_shim.h" +#endif + #include "mem_p.h" #define MCTXLOCK(m) LOCK(&m->lock) diff --git a/m4/ax_jemalloc.m4 b/m4/ax_jemalloc.m4 new file mode 100644 index 0000000000..3d7b463568 --- /dev/null +++ b/m4/ax_jemalloc.m4 @@ -0,0 +1,53 @@ +# =========================================================================== +# https://gitlab.isc.org/isc-projects/autoconf-archive/ax_jemalloc.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_JEMALLOC([, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +# +# DESCRIPTION +# +# Test for the jemalloc library in a path +# +# LICENSE +# +# Copyright (c) 2021 Internet Systems Consortium +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 1 + +# +AC_DEFUN([AX_CHECK_JEMALLOC], [ + found=false + PKG_CHECK_MODULES( + [JEMALLOC], [jemalloc], + [ + found=true + ], [ + AC_CHECK_HEADERS([malloc_np.h jemalloc/jemalloc.h], + [ + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" + save_CPPFLAGS="$CPPFLAGS" + AC_SEARCH_LIBS([mallocx], [jemalloc], + [ + found=true + AS_IF([test "$ac_cv_search_mallocx" != "none required"], + [JEMALLOC_LIBS="$ac_cv_search_mallocx"]) + ]) + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ]) + ]) + + AS_IF([$found], [$1], [$2]) + + AC_SUBST([JEMALLOC_CFLAGS]) + AC_SUBST([JEMALLOC_LIBS]) +]) diff --git a/util/copyrights b/util/copyrights index f982fbae20..68aede72b4 100644 --- a/util/copyrights +++ b/util/copyrights @@ -1787,6 +1787,7 @@ ./lib/isc/include/pkcs11/pkcs11.h X 2019,2020,2021 ./lib/isc/interfaceiter.c C 1999,2000,2001,2002,2003,2004,2005,2007,2008,2014,2016,2017,2018,2019,2020,2021 ./lib/isc/iterated_hash.c C 2006,2008,2009,2016,2018,2019,2020,2021 +./lib/isc/jemalloc_shim.h C 2021 ./lib/isc/lex.c C 1998,1999,2000,2001,2002,2003,2004,2005,2007,2013,2014,2015,2016,2017,2018,2019,2020,2021 ./lib/isc/lib.c C 1999,2000,2001,2004,2005,2007,2009,2013,2014,2015,2016,2018,2019,2020,2021 ./lib/isc/log.c C 1999,2000,2001,2002,2003,2004,2005,2006,2007,2009,2011,2012,2013,2014,2016,2017,2018,2019,2020,2021