From ec532a1eca58c0a5d9cc7330b1cd8d3b3adaf96b Mon Sep 17 00:00:00 2001 From: soarpenguin Date: Fri, 2 Nov 2012 10:33:57 +0800 Subject: [PATCH 1/4] fix __GNUC_MINOR__ >= 6 to 2 it's may be error or just design in __GNUC__ && __GNUC_MINOR__ judgment for #pragma GCC diagnostic ignored "-Wstrict-aliasing" #pragma GCC diagnostic pop --- src/mc_items.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mc_items.h b/src/mc_items.h index 212d7ab..7fffaa7 100644 --- a/src/mc_items.h +++ b/src/mc_items.h @@ -174,7 +174,7 @@ item_set_cas(struct item *it, uint64_t cas) *((uint64_t *)it->end) = cas; } } -#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 6 +#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 2 #pragma GCC diagnostic pop #endif From e1121274c9ee79a709b693cd1c927f2f9bf233f7 Mon Sep 17 00:00:00 2001 From: soarpenguin Date: Mon, 28 Jan 2013 20:33:46 +0800 Subject: [PATCH 2/4] move memory manage code(alloc, zalloc etc) to mc_alloc(.c/.h). --- src/Makefile.am | 1 + src/mc_alloc.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++ src/mc_alloc.h | 74 +++++++++++++++++++++++++++++++++++++ src/mc_core.h | 1 + src/mc_util.c | 61 ------------------------------- src/mc_util.h | 38 ------------------- 6 files changed, 173 insertions(+), 99 deletions(-) create mode 100644 src/mc_alloc.c create mode 100644 src/mc_alloc.h diff --git a/src/Makefile.am b/src/Makefile.am index eef5795..93137e5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -25,4 +25,5 @@ twemcache_SOURCES = \ mc_queue.h \ mc_cache.c mc_cache.h \ mc_klog.c mc_klog.h \ + mc_alloc.c mc_alloc.h \ mc.c diff --git a/src/mc_alloc.c b/src/mc_alloc.c new file mode 100644 index 0000000..a8be01a --- /dev/null +++ b/src/mc_alloc.c @@ -0,0 +1,97 @@ +/* + * twemcache - Twitter memcached. + * Copyright (c) 2012, Twitter, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Twitter nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include + +void * +_mc_alloc(size_t size, const char *name, int line) +{ + void *p; + + ASSERT(size != 0); + + p = malloc(size); + if (p == NULL) { + log_error("malloc(%zu) failed @ %s:%d", size, name, line); + } else { + log_debug(LOG_VVERB, "malloc(%zu) at %p @ %s:%d", size, p, name, line); + } + + return p; +} + +void * +_mc_zalloc(size_t size, const char *name, int line) +{ + void *p; + + p = _mc_alloc(size, name, line); + if (p != NULL) { + memset(p, 0, size); + } + + return p; +} + +void * +_mc_calloc(size_t nmemb, size_t size, const char *name, int line) +{ + return _mc_zalloc(nmemb * size, name, line); +} + +void * +_mc_realloc(void *ptr, size_t size, const char *name, int line) +{ + void *p; + + ASSERT(size != 0); + + p = realloc(ptr, size); + if (p == NULL) { + log_error("realloc(%zu) failed @ %s:%d", size, name, line); + } else { + log_debug(LOG_VVERB, "realloc(%zu) at %p @ %s:%d", size, p, name, line); + } + + return p; +} + +void +_mc_free(void *ptr, const char *name, int line) +{ + ASSERT(ptr != NULL); + log_debug(LOG_VVERB, "free(%p) @ %s:%d", ptr, name, line); + free(ptr); +} diff --git a/src/mc_alloc.h b/src/mc_alloc.h new file mode 100644 index 0000000..c38bb0b --- /dev/null +++ b/src/mc_alloc.h @@ -0,0 +1,74 @@ +/* + * twemcache - Twitter memcached. + * Copyright (c) 2012, Twitter, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Twitter nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MC_ALLOC_H_ +#define _MC_ALLOC_H_ + +#include +#include + +/* + * Make data 'd' or pointer 'p', n-byte aligned, where n is a power of 2 + * of 2. + */ +#define MC_ALIGNMENT sizeof(unsigned long) /* platform word */ +#define MC_ALIGN(d, n) ((size_t)(((d) + (n - 1)) & ~(n - 1))) +#define MC_ALIGN_PTR(p, n) \ + (void *) (((uintptr_t) (p) + ((uintptr_t) n - 1)) & ~((uintptr_t) n - 1)) + +/* + * Memory allocation and free wrappers. + * + * These wrappers enables us to loosely detect double free, dangling + * pointer access and zero-byte alloc. + */ +#define mc_alloc(_s) \ + _mc_alloc((size_t)(_s), __FILE__, __LINE__) + +#define mc_zalloc(_s) \ + _mc_zalloc((size_t)(_s), __FILE__, __LINE__) + +#define mc_calloc(_n, _s) \ + _mc_calloc((size_t)(_n), (size_t)(_s), __FILE__, __LINE__) + +#define mc_realloc(_p, _s) \ + _mc_realloc(_p, (size_t)(_s), __FILE__, __LINE__) + +#define mc_free(_p) do { \ + _mc_free(_p, __FILE__, __LINE__); \ + (_p) = NULL; \ +} while (0) + +void *_mc_alloc(size_t size, const char *name, int line); +void *_mc_zalloc(size_t size, const char *name, int line); +void *_mc_calloc(size_t nmemb, size_t size, const char *name, int line); +void *_mc_realloc(void *ptr, size_t size, const char *name, int line); +void _mc_free(void *ptr, const char *name, int line); + +#endif diff --git a/src/mc_core.h b/src/mc_core.h index fcace35..b3db198 100644 --- a/src/mc_core.h +++ b/src/mc_core.h @@ -133,6 +133,7 @@ struct slabclass; #include #include #include +#include /* * request min max noreply noreply diff --git a/src/mc_util.c b/src/mc_util.c index 169332f..c505f0d 100644 --- a/src/mc_util.c +++ b/src/mc_util.c @@ -483,67 +483,6 @@ _scnprintf(char *buf, size_t size, const char *fmt, ...) return i; } -void * -_mc_alloc(size_t size, const char *name, int line) -{ - void *p; - - ASSERT(size != 0); - - p = malloc(size); - if (p == NULL) { - log_error("malloc(%zu) failed @ %s:%d", size, name, line); - } else { - log_debug(LOG_VVERB, "malloc(%zu) at %p @ %s:%d", size, p, name, line); - } - - return p; -} - -void * -_mc_zalloc(size_t size, const char *name, int line) -{ - void *p; - - p = _mc_alloc(size, name, line); - if (p != NULL) { - memset(p, 0, size); - } - - return p; -} - -void * -_mc_calloc(size_t nmemb, size_t size, const char *name, int line) -{ - return _mc_zalloc(nmemb * size, name, line); -} - -void * -_mc_realloc(void *ptr, size_t size, const char *name, int line) -{ - void *p; - - ASSERT(size != 0); - - p = realloc(ptr, size); - if (p == NULL) { - log_error("realloc(%zu) failed @ %s:%d", size, name, line); - } else { - log_debug(LOG_VVERB, "realloc(%zu) at %p @ %s:%d", size, p, name, line); - } - - return p; -} - -void -_mc_free(void *ptr, const char *name, int line) -{ - ASSERT(ptr != NULL); - log_debug(LOG_VVERB, "free(%p) @ %s:%d", ptr, name, line); - free(ptr); -} - void mc_assert(const char *cond, const char *file, int line, int panic) { diff --git a/src/mc_util.h b/src/mc_util.h index 20e2153..3717ae2 100644 --- a/src/mc_util.h +++ b/src/mc_util.h @@ -64,44 +64,6 @@ #define MC_UINT64_MAXLEN (20 + 1) #define MC_UINTMAX_MAXLEN MC_UINT64_MAXLEN -/* - * Make data 'd' or pointer 'p', n-byte aligned, where n is a power of 2 - * of 2. - */ -#define MC_ALIGNMENT sizeof(unsigned long) /* platform word */ -#define MC_ALIGN(d, n) ((size_t)(((d) + (n - 1)) & ~(n - 1))) -#define MC_ALIGN_PTR(p, n) \ - (void *) (((uintptr_t) (p) + ((uintptr_t) n - 1)) & ~((uintptr_t) n - 1)) - -/* - * Memory allocation and free wrappers. - * - * These wrappers enables us to loosely detect double free, dangling - * pointer access and zero-byte alloc. - */ -#define mc_alloc(_s) \ - _mc_alloc((size_t)(_s), __FILE__, __LINE__) - -#define mc_zalloc(_s) \ - _mc_zalloc((size_t)(_s), __FILE__, __LINE__) - -#define mc_calloc(_n, _s) \ - _mc_calloc((size_t)(_n), (size_t)(_s), __FILE__, __LINE__) - -#define mc_realloc(_p, _s) \ - _mc_realloc(_p, (size_t)(_s), __FILE__, __LINE__) - -#define mc_free(_p) do { \ - _mc_free(_p, __FILE__, __LINE__); \ - (_p) = NULL; \ -} while (0) - -void *_mc_alloc(size_t size, const char *name, int line); -void *_mc_zalloc(size_t size, const char *name, int line); -void *_mc_calloc(size_t nmemb, size_t size, const char *name, int line); -void *_mc_realloc(void *ptr, size_t size, const char *name, int line); -void _mc_free(void *ptr, const char *name, int line); - int mc_set_blocking(int sd); int mc_set_nonblocking(int sd); int mc_set_reuseaddr(int sd); From 79a63e6ec4630525d9a85b375ef439db6d566313 Mon Sep 17 00:00:00 2001 From: soarpenguin Date: Sun, 3 Feb 2013 20:47:01 +0800 Subject: [PATCH 3/4] add (heap_curr) a metric for current heap memory usage. --- configure.ac | 215 +++++++++++++++++++++++++++++++++++++++++++++++++ src/mc_alloc.c | 178 +++++++++++++++++++++++++++++++++++++++- src/mc_alloc.h | 51 ++++++++++++ src/mc_items.h | 2 +- src/mc_stats.c | 1 + src/mc_util.c | 2 +- 6 files changed, 443 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index b235c16..9ab920d 100644 --- a/configure.ac +++ b/configure.ac @@ -231,6 +231,221 @@ AS_IF( ] ) +# Libjemalloc detection; +trylibjemallocdir="" +AC_ARG_WITH([libjemalloc], + [AS_HELP_STRING([--with-libjemalloc=@<:@path@:>@], [specify path to libjemalloc install])], + [trylibjemallocdir=$withval], [] +) +LIBJEMALLOC_URL=http://www.canonware.com/jemalloc/ +AC_CACHE_CHECK([for libjemalloc directory], [ac_cv_libjemalloc_dir], + [ + saved_LIBS="$LIBS" + saved_LDFLAGS="$LDFLAGS" + saved_CPPFLAGS="$CPPFLAGS" + lj_found=no + for ljdir in $trylibjemallocdir "" $prefix /usr/local + do + LDFLAGS="$saved_LDFLAGS" + LIBS="-ljemalloc $saved_LIBS" + + # Skip the directory if it isn't there. + AS_IF([test ! -z "$ljdir" -a ! -d "$ljdir"], [continue]) + AS_IF( + [test ! -z "$ljdir"], + [ + AS_IF( + [test -d "$ljdir/lib"], + [LDFLAGS="-L$ljdir/lib $LDFLAGS"], + [LDFLAGS="-L$ljdir $LDFLAGS"] + ) + AS_IF( + [test -d "$ljdir/include"], + [CPPFLAGS="-I$ljdir/include $CPPFLAGS"], + [CPPFLAGS="-I$ljdir $CPPFLAGS"] + ) + ] + ) + + # Can I compile and link it? + AC_TRY_LINK( + [ + #include + #include + #include + ], + [ + int length = 0; + char *ptr = (char*)jemalloc(4); + length = jemalloc_usable_size(ptr); + jefree(ptr); + ], + [libjemalloc_linked=yes], + [libjemalloc_linked=no] + ) + AS_IF( + [test $libjemalloc_linked = yes], + [ + AS_IF( + [test ! -z "$ljdir"], + [ac_cv_libjemalloc_dir=$ljdir], + [ac_cv_libjemalloc_dir="(system)"] + ) + lj_found=yes + break + ] + ) + done + LIBS="$saved_LIBS" + LDFLAGS="$saved_LDFLAGS" + CPPFLAGS="$saved_CPPFLAGS" +# AS_IF( +# [test $lj_found = no], +# [AC_MSG_ERROR([libjemalloc required. Get it from $LIBJEMALLOC_URL or specify its path using --with-libjemalloc=/dir/])] +# ) + ] +) +AS_IF( + [test $ac_cv_libjemalloc_dir != "(system)"], + [ + AS_IF( + [test -d "$ac_cv_libjemalloc_dir/lib"], + [ + LDFLAGS="-L$ac_cv_libjemalloc_dir/lib $LDFLAGS" + lj_libdir="$ac_cv_libjemalloc_dir/lib" + ], + [ + LDFLAGS="-L$ac_cv_libjemalloc_dir $LDFLAGS" + lj_libdir="$ac_cv_libjemalloc_dir" + ] + ) + AS_IF( + [test -d "$ac_cv_libjemalloc_dir/include"], + [CPPFLAGS="-I$ac_cv_libjemalloc_dir/include $CPPFLAGS"] + [CPPFLAGS="-I$ac_cv_libjemalloc_dir $CPPFLAGS"] + ) + ] +) + +AS_IF( + [test $lj_found != yes], + [ +# Libtcmalloc detection; +trylibtcmallocdir="" +AC_ARG_WITH([libtcmalloc], + [AS_HELP_STRING([--with-libtcmalloc=@<:@path@:>@], [specify path to libtcmalloc install])], + [trylibtcmallocdir=$withval], [] +) +LIBTCMALLOC_URL=http://code.google.com/p/gperftools/ +AC_CACHE_CHECK([for libtcmalloc directory], [ac_cv_libtcmalloc_dir], + [ + saved_LIBS="$LIBS" + saved_LDFLAGS="$LDFLAGS" + saved_CPPFLAGS="$CPPFLAGS" + lt_found=no + for ltdir in $trylibtcmallocdir "" $prefix /usr/local + do + LDFLAGS="$saved_LDFLAGS" + LIBS="-ltcmalloc $saved_LIBS" + + # Skip the directory if it isn't there. + AS_IF([test ! -z "$ltdir" -a ! -d "$ltdir"], [continue]) + AS_IF( + [test ! -z "$ltdir"], + [ + AS_IF( + [test -d "$ltdir/lib"], + [LDFLAGS="-L$ltdir/lib $LDFLAGS"], + [LDFLAGS="-L$ltdir $LDFLAGS"] + ) + AS_IF( + [test -d "$ltdir/include"], + [CPPFLAGS="-I$ltdir/include $CPPFLAGS"], + [CPPFLAGS="-I$ltdir $CPPFLAGS"] + ) + ] + ) + + # Can I compile and link it? + AC_TRY_LINK( + [ + #include + #include + #include + ], + [ + int length = 0; + char *ptr = (char*)tc_malloc(4); + length = tc_malloc_size(ptr); + tc_free(ptr); + ], + [libtcmalloc_linked=yes], + [libtcmalloc_linked=no] + ) + AS_IF( + [test $libtcmalloc_linked = yes], + [ + AS_IF( + [test ! -z "$ltdir"], + [ac_cv_libtcmalloc_dir=$ltdir], + [ac_cv_libtcmalloc_dir="(system)"] + ) + lt_found=yes + break + ] + ) + done + LIBS="$saved_LIBS" + LDFLAGS="$saved_LDFLAGS" + CPPFLAGS="$saved_CPPFLAGS" +# AS_IF( +# [test $lt_found = no], +# [AC_MSG_ERROR([libtcmalloc required. Get it from $LIBTCMALLOC_URL or specify its path using --with-libtcmalloc=/dir/])] +# ) + ] +) +AS_IF( + [test $ac_cv_libtcmalloc_dir != "(system)"], + [ + AS_IF( + [test -d "$ac_cv_libtcmalloc_dir/lib"], + [ + LDFLAGS="-L$ac_cv_libtcmalloc_dir/lib $LDFLAGS" + lt_libdir="$ac_cv_libtcmalloc_dir/lib" + ], + [ + LDFLAGS="-L$ac_cv_libtcmalloc_dir $LDFLAGS" + lt_libdir="$ac_cv_libtcmalloc_dir" + ] + ) + AS_IF( + [test -d "$ac_cv_libtcmalloc_dir/include"], + [CPPFLAGS="-I$ac_cv_libtcmalloc_dir/include $CPPFLAGS"] + [CPPFLAGS="-I$ac_cv_libtcmalloc_dir $CPPFLAGS"] + ) + ] +) + + ] +) #end for AS_IF before Libtcmalloc detection + +AS_IF( + [test $lj_found = yes], + [ + CFLAGS="$CFLAGS -DUSE_JEMALLOC" + LIBS="-ljemalloc $LIBS" + ], + [ + AS_IF( + [test $lj_found != yes -a $lt_found = yes], + [ + CFLAGS="$CFLAGS -DUSE_TCMALLOC" + LIBS="-ltcmalloc $LIBS" + ] + ) + ] +) + # Check whether to enable static linking AC_MSG_CHECKING([whether to enable static linking]) AC_ARG_ENABLE([static], diff --git a/src/mc_alloc.c b/src/mc_alloc.c index a8be01a..72f6a05 100644 --- a/src/mc_alloc.c +++ b/src/mc_alloc.c @@ -31,10 +31,93 @@ #include #include #include -#include +#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 2 +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#endif + +/* This function provide us access to the original libc free(). This is useful + * for instance to free results obtained by backtrace_symbols(). We need + * to define this function before including mc_alloc.h that may shadow the + * free implementation if we use jemalloc or another non standard allocator. */ +void +mc_libc_free(void *ptr) +{ + free(ptr); +} +#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 6 +#pragma GCC diagnostic pop +#endif + +#include #include +#ifdef HAVE_MALLOC_SIZE +#define PREFIX_SIZE (0) +#else +#if defined(__sun) || defined(__sparc) || defined(__sparc__) +#define PREFIX_SIZE (sizeof(long long)) +#else +#define PREFIX_SIZE (sizeof(size_t)) +#endif +#endif + +#if defined(USE_TCMALLOC) +#define malloc(size) tc_malloc(size) +#define calloc(count, size) tc_calloc(count, size) +#define realloc(ptr, size) tc_realloc(ptr, size) +#define free(ptr) tc_free(ptr); +#elif defined(USE_JEMALLOC) +#define malloc(size) jemalloc(size) +#define calloc(count, size) jecalloc(count, size) +#define realloc(ptr, size) jerealloc(ptr, size) +#define free(ptr) jefree(ptr); +#endif + +#ifdef HAVE_ATOMIC +#define update_mcmalloc_stat_add(__n) __sync_add_and_fetch(&heap_curr, (__n)) +#define update_mcmalloc_stat_sub(__n) __sync_sub_and_fetch(&heap_curr, (__n)) +#else +#define update_mcmalloc_stat_add(__n) do { \ + pthread_mutex_lock(&heap_curr_mutex); \ + heap_curr += (__n); \ + pthread_mutex_unlock(&heap_curr_mutex); \ +} while(0) + +#define update_mcmalloc_stat_sub(__n) do { \ + pthread_mutex_lock(&heap_curr_mutex); \ + heap_curr -= (__n); \ + pthread_mutex_unlock(&heap_curr_mutex); \ +} while(0) + +#endif + +#define update_mcmalloc_stat_alloc(__n) do { \ + size_t _n = (__n); \ + if (_n & (sizeof(long) - 1)) \ + _n += sizeof(long)-(_n & (sizeof(long)-1)); \ + if (mc_malloc_thread_safe) { \ + update_mcmalloc_stat_add(_n); \ + } else { \ + heap_curr += _n; \ + } \ +} while(0) + +#define update_mcmalloc_stat_free(__n) do { \ + size_t _n = (__n); \ + if (_n & (sizeof(long)-1)) \ + _n += sizeof(long) - (_n & (sizeof(long)-1)); \ + if (mc_malloc_thread_safe) { \ + update_mcmalloc_stat_sub(_n); \ + } else { \ + heap_curr -= _n; \ + } \ +} while(0) + +static size_t heap_curr = 0; +static int mc_malloc_thread_safe = 1; +pthread_mutex_t heap_curr_mutex = PTHREAD_MUTEX_INITIALIZER; + void * _mc_alloc(size_t size, const char *name, int line) { @@ -42,14 +125,23 @@ _mc_alloc(size_t size, const char *name, int line) ASSERT(size != 0); - p = malloc(size); + p = malloc(size + PREFIX_SIZE); if (p == NULL) { log_error("malloc(%zu) failed @ %s:%d", size, name, line); + return p; } else { - log_debug(LOG_VVERB, "malloc(%zu) at %p @ %s:%d", size, p, name, line); + log_debug(LOG_VVERB, "malloc(%zu) at %p @ %s:%d", + size + PREFIX_SIZE, p, name, line); } +#ifdef HAVE_MALLOC_SIZE + update_mcmalloc_stat_alloc(size + PREFIX_SIZE); return p; +#else + *((size_t*)p) = size; + update_mcmalloc_stat_alloc(size + PREFIX_SIZE); + return (char *)p + PREFIX_SIZE; +#endif } void * @@ -74,24 +166,102 @@ _mc_calloc(size_t nmemb, size_t size, const char *name, int line) void * _mc_realloc(void *ptr, size_t size, const char *name, int line) { +#ifndef HAVE_MALLOC_SIZE + void *realptr; +#endif + size_t oldsize; void *p; ASSERT(size != 0); + if (ptr == NULL) + return _mc_alloc(size, name, line); + +#ifdef HAVE_MALLOC_SIZE + oldsize = mc_alloc_size(ptr); p = realloc(ptr, size); +#else + realptr = (char*)ptr - PREFIX_SIZE; + oldsize = *((size_t*)realptr); + + p = realloc(realptr, size + PREFIX_SIZE); +#endif + if (p == NULL) { log_error("realloc(%zu) failed @ %s:%d", size, name, line); + return p; } else { log_debug(LOG_VVERB, "realloc(%zu) at %p @ %s:%d", size, p, name, line); } - return p; +#ifdef HAVE_MALLOC_SIZE + update_mcmalloc_stat_free(oldsize); + update_mcmalloc_stat_alloc(mc_alloc_size(p)); +#else + *((size_t*)p) = size; + update_mcmalloc_stat_free(oldsize); + update_mcmalloc_stat_alloc(size); +#endif + + return (char*)p + PREFIX_SIZE; +} + +/* Provide mc_alloc_size() for systems where this function is not provided by + * malloc itself, given that in that case we store an header with this + * information as the first bytes of every allocation. */ +#ifndef HAVE_MALLOC_SIZE +size_t +mc_alloc_size(void *ptr) +{ + void *realptr = (char*)ptr - PREFIX_SIZE; + size_t size = *((size_t*)realptr); + + /* Assume at least that all the allocations are padded at sizeof(long) by + * the underlying allocator. */ + if (size & (sizeof(long) - 1)) + size += sizeof(long) - (size & (sizeof(long) - 1)); + + return size + PREFIX_SIZE; } +#endif void _mc_free(void *ptr, const char *name, int line) { ASSERT(ptr != NULL); + +#ifndef HAVE_MALLOC_SIZE + int oldsize; + ptr = (char*)ptr - PREFIX_SIZE; +#endif + log_debug(LOG_VVERB, "free(%p) @ %s:%d", ptr, name, line); +#ifdef HAVE_MALLOC_SIZE + update_mcmalloc_stat_free(mc_alloc_size(ptr)); +#else + oldsize = *((size_t*)ptr); + update_mcmalloc_stat_free(oldsize + PREFIX_SIZE); +#endif + free(ptr); } + +size_t +mc_malloc_used_memory(void) +{ + size_t hc = 0; + + if (mc_malloc_thread_safe) { +#ifdef HAVE_ATOMIC + hc = __sync_add_and_fetch(&heap_curr, 0); +#else + pthread_mutex_lock(&heap_curr_mutex); + hc = heap_curr; + pthread_mutex_unlock(&heap_curr_mutex); +#endif + } else { + hc = heap_curr; + } + + return hc; +} diff --git a/src/mc_alloc.h b/src/mc_alloc.h index c38bb0b..a3f5dad 100644 --- a/src/mc_alloc.h +++ b/src/mc_alloc.h @@ -33,6 +33,43 @@ #include #include +/* Double expansion needed for stringification of macro values. */ +#define __xstr(s) __str(s) +#define __str(s) #s + +#if defined(USE_TCMALLOC) +#define MC_MALLOC_LIB \ + ("tcmalloc-" __xstr(TC_VERSION_MAJOR) "." __xstr(TC_VERSION_MINOR)) +#include +#if (TC_VERSION_MAJOR == 1 && TC_VERSION_MINOR >= 6) || (TC_VERSION_MAJOR > 1) +#define HAVE_MALLOC_SIZE 1 +#define mc_alloc_size(p) tc_malloc_size(p) +#else +#error "Newer version of tcmalloc required" +#endif + +#elif defined(USE_JEMALLOC) +#define MC_MALLOC_LIB \ + ("jemalloc-" __xstr(JEMALLOC_VERSION_MAJOR) "." __xstr(JEMALLOC_VERSION_MINOR)) +#include +#if (JEMALLOC_VERSION_MAJOR == 2 && JEMALLOC_VERSION_MINOR >= 1) || \ + (JEMALLOC_VERSION_MAJOR > 2) +#define HAVE_MALLOC_SIZE 1 +#define mc_alloc_size(p) jemalloc_usable_size(p) +#else +#error "Newer version of jemalloc required" +#endif + +#elif defined(__APPLE__) +#include +#define HAVE_MALLOC_SIZE 1 +#define mc_alloc_size malloc_size(p) +#endif + +#ifndef MC_MALLOC_LIB +#define MC_MALLOC_LIB "libc" +#endif + /* * Make data 'd' or pointer 'p', n-byte aligned, where n is a power of 2 * of 2. @@ -70,5 +107,19 @@ void *_mc_zalloc(size_t size, const char *name, int line); void *_mc_calloc(size_t nmemb, size_t size, const char *name, int line); void *_mc_realloc(void *ptr, size_t size, const char *name, int line); void _mc_free(void *ptr, const char *name, int line); +size_t mc_malloc_used_memory(void); + +#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 2 +#pragma GCC diagnostic ignored "-Wredundant-decls" +#endif + +void mc_libc_free(void *ptr); +#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 6 +#pragma GCC diagnostic pop +#endif + +#ifndef HAVE_MALLOC_SIZE +size_t mc_alloc_size(void *ptr); +#endif #endif diff --git a/src/mc_items.h b/src/mc_items.h index 6736f66..a9a3df1 100644 --- a/src/mc_items.h +++ b/src/mc_items.h @@ -174,7 +174,7 @@ item_set_cas(struct item *it, uint64_t cas) *((uint64_t *)it->end) = cas; } } -#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 2 +#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 6 #pragma GCC diagnostic pop #endif diff --git a/src/mc_stats.c b/src/mc_stats.c index 2965161..6411f97 100644 --- a/src/mc_stats.c +++ b/src/mc_stats.c @@ -695,6 +695,7 @@ stats_default(struct conn *c) usage.ru_utime.tv_usec); stats_print(c, "rusage_system", "%ld.%06ld", usage.ru_stime.tv_sec, usage.ru_stime.tv_usec); + stats_print(c, "heap_curr", "%ld", mc_malloc_used_memory()); sem_wait(&aggregator.stats_sem); diff --git a/src/mc_util.c b/src/mc_util.c index c505f0d..66ca450 100644 --- a/src/mc_util.c +++ b/src/mc_util.c @@ -513,7 +513,7 @@ mc_stacktrace(int skip_count) loga("[%d] %s", j, symbols[i]); } - free(symbols); + mc_libc_free(symbols); #endif } From 89615c735e892594af22bb120dfbb04fd2b0eabf Mon Sep 17 00:00:00 2001 From: soarpenguin Date: Sat, 16 Feb 2013 20:56:56 +0800 Subject: [PATCH 4/4] add metrics for current hashtable size and connection buffer usage. --- src/mc_assoc.c | 18 ++++++++++++++++++ src/mc_assoc.h | 1 + src/mc_connection.c | 28 ++++++++++++++++++++++++++++ src/mc_connection.h | 2 ++ src/mc_stats.c | 2 ++ 5 files changed, 51 insertions(+) diff --git a/src/mc_assoc.c b/src/mc_assoc.c index 5b49769..c464f68 100644 --- a/src/mc_assoc.c +++ b/src/mc_assoc.c @@ -303,3 +303,21 @@ assoc_delete(const char *key, size_t nkey) nhash_item--; } + +size_t +mc_get_heap_hashtable(void) +{ + size_t hh = 0; + + if (primary_hashtable == NULL && old_hashtable == NULL) { + return hh; + } + + if (expanding) { + hh = HASHSIZE(hash_power) + HASHSIZE(hash_power - 1); + } else { + hh = HASHSIZE(hash_power); + } + + return (size_t)(hh * sizeof(struct item_slh)); +} diff --git a/src/mc_assoc.h b/src/mc_assoc.h index 5c8c9f6..3c3632d 100644 --- a/src/mc_assoc.h +++ b/src/mc_assoc.h @@ -38,5 +38,6 @@ void assoc_deinit(void); struct item *assoc_find(const char *key, size_t nkey); void assoc_insert(struct item *item); void assoc_delete(const char *key, size_t nkey); +size_t mc_get_heap_hashtable(void); #endif diff --git a/src/mc_connection.c b/src/mc_connection.c index 136b852..1796fa1 100644 --- a/src/mc_connection.c +++ b/src/mc_connection.c @@ -39,6 +39,10 @@ static uint32_t nfree_connq; /* # free conn q */ static struct conn_tqh free_connq; /* free conn q */ static pthread_mutex_t free_connq_mutex; /* free conn q mutex */ +static size_t heap_conn = 0; /* total struct conn heap usage */ +static int mc_heap_conn_thread_safe = 1; +pthread_mutex_t heap_conn_mutex = PTHREAD_MUTEX_INITIALIZER;/*heap_conn mutex*/ + void conn_cq_init(struct conn_q *cq) { @@ -123,6 +127,10 @@ conn_free(struct conn *c) mc_free(c->iov); } + pthread_mutex_lock(&heap_conn_mutex); + heap_conn -= (sizeof(*c) + c->rsize + c->wsize); + pthread_mutex_unlock(&heap_conn_mutex); + mc_free(c); } @@ -204,6 +212,10 @@ conn_get(int sd, conn_state_t state, int ev_flags, int rsize, int udp) } stats_thread_incr(conn_struct); + + pthread_mutex_lock(&heap_conn_mutex); + heap_conn += (sizeof(*c) + c->rsize + c->wsize); + pthread_mutex_unlock(&heap_conn_mutex); } STAILQ_NEXT(c, c_tqe) = NULL; @@ -606,3 +618,19 @@ conn_build_udp_headers(struct conn *c) return MC_OK; } + +size_t +mc_get_heap_conn(void) +{ + size_t hc = 0; + + if (mc_heap_conn_thread_safe) { + pthread_mutex_lock(&heap_conn_mutex); + hc = heap_conn; + pthread_mutex_unlock(&heap_conn_mutex); + } else { + hc = heap_conn; + } + + return hc; +} diff --git a/src/mc_connection.h b/src/mc_connection.h index 2d0b9d5..69b1263 100644 --- a/src/mc_connection.h +++ b/src/mc_connection.h @@ -169,4 +169,6 @@ void conn_set_state(struct conn *c, conn_state_t state); rstatus_t conn_set_event(struct conn *conn, struct event_base *base); +size_t mc_get_heap_conn(void); + #endif diff --git a/src/mc_stats.c b/src/mc_stats.c index 6411f97..45c6acb 100644 --- a/src/mc_stats.c +++ b/src/mc_stats.c @@ -696,6 +696,8 @@ stats_default(struct conn *c) stats_print(c, "rusage_system", "%ld.%06ld", usage.ru_stime.tv_sec, usage.ru_stime.tv_usec); stats_print(c, "heap_curr", "%ld", mc_malloc_used_memory()); + stats_print(c, "heap_hashtable", "%ld", mc_get_heap_hashtable()); + stats_print(c, "heap_conn", "%ld", mc_get_heap_conn()); sem_wait(&aggregator.stats_sem);