LCOV - code coverage report
Current view: directory - redis/src - zmalloc.c (source / functions) Found Hit Coverage
Test: redis.info Lines: 63 53 84.1 %
Date: 2012-04-04 Functions: 11 9 81.8 %
Colors: not hit hit

       1                 : /* zmalloc - total amount of allocated memory aware version of malloc()
       2                 :  *
       3                 :  * Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
       4                 :  * All rights reserved.
       5                 :  *
       6                 :  * Redistribution and use in source and binary forms, with or without
       7                 :  * modification, are permitted provided that the following conditions are met:
       8                 :  *
       9                 :  *   * Redistributions of source code must retain the above copyright notice,
      10                 :  *     this list of conditions and the following disclaimer.
      11                 :  *   * Redistributions in binary form must reproduce the above copyright
      12                 :  *     notice, this list of conditions and the following disclaimer in the
      13                 :  *     documentation and/or other materials provided with the distribution.
      14                 :  *   * Neither the name of Redis nor the names of its contributors may be used
      15                 :  *     to endorse or promote products derived from this software without
      16                 :  *     specific prior written permission.
      17                 :  *
      18                 :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
      19                 :  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      20                 :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      21                 :  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
      22                 :  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      23                 :  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
      24                 :  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      25                 :  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
      26                 :  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      27                 :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      28                 :  * POSSIBILITY OF SUCH DAMAGE.
      29                 :  */
      30                 : 
      31                 : #include <stdio.h>
      32                 : #include <stdlib.h>
      33                 : 
      34                 : /* This function provide us access to the original libc free(). This is useful
      35                 :  * for instance to free results obtained by backtrace_symbols(). We need
      36                 :  * to define this function before including zmalloc.h that may shadow the
      37                 :  * free implementation if we use jemalloc or another non standard allocator. */
      38               0 : void zlibc_free(void *ptr) {
      39               0 :     free(ptr);
      40               0 : }
      41                 : 
      42                 : #include <string.h>
      43                 : #include <pthread.h>
      44                 : #include "config.h"
      45                 : #include "zmalloc.h"
      46                 : 
      47                 : #ifdef HAVE_MALLOC_SIZE
      48                 : #define PREFIX_SIZE (0)
      49                 : #else
      50                 : #if defined(__sun) || defined(__sparc) || defined(__sparc__)
      51                 : #define PREFIX_SIZE (sizeof(long long))
      52                 : #else
      53                 : #define PREFIX_SIZE (sizeof(size_t))
      54                 : #endif
      55                 : #endif
      56                 : 
      57                 : /* Explicitly override malloc/free etc when using tcmalloc. */
      58                 : #if defined(USE_TCMALLOC)
      59                 : #define malloc(size) tc_malloc(size)
      60                 : #define calloc(count,size) tc_calloc(count,size)
      61                 : #define realloc(ptr,size) tc_realloc(ptr,size)
      62                 : #define free(ptr) tc_free(ptr)
      63                 : #elif defined(USE_JEMALLOC)
      64                 : #define malloc(size) je_malloc(size)
      65                 : #define calloc(count,size) je_calloc(count,size)
      66                 : #define realloc(ptr,size) je_realloc(ptr,size)
      67                 : #define free(ptr) je_free(ptr)
      68                 : #endif
      69                 : 
      70                 : #ifdef HAVE_ATOMIC
      71                 : #define update_zmalloc_stat_add(__n) __sync_add_and_fetch(&used_memory, (__n))
      72                 : #define update_zmalloc_stat_sub(__n) __sync_sub_and_fetch(&used_memory, (__n))
      73                 : #else
      74                 : #define update_zmalloc_stat_add(__n) do { \
      75                 :     pthread_mutex_lock(&used_memory_mutex); \
      76                 :     used_memory += (__n); \
      77                 :     pthread_mutex_unlock(&used_memory_mutex); \
      78                 : } while(0)
      79                 : 
      80                 : #define update_zmalloc_stat_sub(__n) do { \
      81                 :     pthread_mutex_lock(&used_memory_mutex); \
      82                 :     used_memory -= (__n); \
      83                 :     pthread_mutex_unlock(&used_memory_mutex); \
      84                 : } while(0)
      85                 : 
      86                 : #endif
      87                 : 
      88                 : #define update_zmalloc_stat_alloc(__n,__size) do { \
      89                 :     size_t _n = (__n); \
      90                 :     if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
      91                 :     if (zmalloc_thread_safe) { \
      92                 :         update_zmalloc_stat_add(_n); \
      93                 :     } else { \
      94                 :         used_memory += _n; \
      95                 :     } \
      96                 : } while(0)
      97                 : 
      98                 : #define update_zmalloc_stat_free(__n) do { \
      99                 :     size_t _n = (__n); \
     100                 :     if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
     101                 :     if (zmalloc_thread_safe) { \
     102                 :         update_zmalloc_stat_sub(_n); \
     103                 :     } else { \
     104                 :         used_memory -= _n; \
     105                 :     } \
     106                 : } while(0)
     107                 : 
     108                 : static size_t used_memory = 0;
     109                 : static int zmalloc_thread_safe = 0;
     110                 : pthread_mutex_t used_memory_mutex = PTHREAD_MUTEX_INITIALIZER;
     111                 : 
     112               0 : static void zmalloc_oom(size_t size) {
     113               0 :     fprintf(stderr, "zmalloc: Out of memory trying to allocate %zu bytes\n",
     114                 :         size);
     115               0 :     fflush(stderr);
     116               0 :     abort();
     117                 : }
     118                 : 
     119        28109759 : void *zmalloc(size_t size) {
     120        28109759 :     void *ptr = malloc(size+PREFIX_SIZE);
     121                 : 
     122        28109759 :     if (!ptr) zmalloc_oom(size);
     123                 : #ifdef HAVE_MALLOC_SIZE
     124        28109759 :     update_zmalloc_stat_alloc(zmalloc_size(ptr),size);
     125        28109759 :     return ptr;
     126                 : #else
     127                 :     *((size_t*)ptr) = size;
     128                 :     update_zmalloc_stat_alloc(size+PREFIX_SIZE,size);
     129                 :     return (char*)ptr+PREFIX_SIZE;
     130                 : #endif
     131                 : }
     132                 : 
     133         2051758 : void *zcalloc(size_t size) {
     134         2051758 :     void *ptr = calloc(1, size+PREFIX_SIZE);
     135                 : 
     136         2051758 :     if (!ptr) zmalloc_oom(size);
     137                 : #ifdef HAVE_MALLOC_SIZE
     138         2051758 :     update_zmalloc_stat_alloc(zmalloc_size(ptr),size);
     139         2051758 :     return ptr;
     140                 : #else
     141                 :     *((size_t*)ptr) = size;
     142                 :     update_zmalloc_stat_alloc(size+PREFIX_SIZE,size);
     143                 :     return (char*)ptr+PREFIX_SIZE;
     144                 : #endif
     145                 : }
     146                 : 
     147          682260 : void *zrealloc(void *ptr, size_t size) {
     148                 : #ifndef HAVE_MALLOC_SIZE
     149                 :     void *realptr;
     150                 : #endif
     151                 :     size_t oldsize;
     152                 :     void *newptr;
     153                 : 
     154          682260 :     if (ptr == NULL) return zmalloc(size);
     155                 : #ifdef HAVE_MALLOC_SIZE
     156          680984 :     oldsize = zmalloc_size(ptr);
     157          680984 :     newptr = realloc(ptr,size);
     158          680984 :     if (!newptr) zmalloc_oom(size);
     159                 : 
     160          680984 :     update_zmalloc_stat_free(oldsize);
     161          680984 :     update_zmalloc_stat_alloc(zmalloc_size(newptr),size);
     162          680984 :     return newptr;
     163                 : #else
     164                 :     realptr = (char*)ptr-PREFIX_SIZE;
     165                 :     oldsize = *((size_t*)realptr);
     166                 :     newptr = realloc(realptr,size+PREFIX_SIZE);
     167                 :     if (!newptr) zmalloc_oom(size);
     168                 : 
     169                 :     *((size_t*)newptr) = size;
     170                 :     update_zmalloc_stat_free(oldsize);
     171                 :     update_zmalloc_stat_alloc(size,size);
     172                 :     return (char*)newptr+PREFIX_SIZE;
     173                 : #endif
     174                 : }
     175                 : 
     176                 : /* Provide zmalloc_size() for systems where this function is not provided by
     177                 :  * malloc itself, given that in that case we store an header with this
     178                 :  * information as the first bytes of every allocation. */
     179                 : #ifndef HAVE_MALLOC_SIZE
     180                 : size_t zmalloc_size(void *ptr) {
     181                 :     void *realptr = (char*)ptr-PREFIX_SIZE;
     182                 :     size_t size = *((size_t*)realptr);
     183                 :     /* Assume at least that all the allocations are padded at sizeof(long) by
     184                 :      * the underlying allocator. */
     185                 :     if (size&(sizeof(long)-1)) size += sizeof(long)-(size&(sizeof(long)-1));
     186                 :     return size+PREFIX_SIZE;
     187                 : }
     188                 : #endif
     189                 : 
     190        22654458 : void zfree(void *ptr) {
     191                 : #ifndef HAVE_MALLOC_SIZE
     192                 :     void *realptr;
     193                 :     size_t oldsize;
     194                 : #endif
     195                 : 
     196        22654458 :     if (ptr == NULL) return;
     197                 : #ifdef HAVE_MALLOC_SIZE
     198        22641689 :     update_zmalloc_stat_free(zmalloc_size(ptr));
     199        22641689 :     free(ptr);
     200                 : #else
     201                 :     realptr = (char*)ptr-PREFIX_SIZE;
     202                 :     oldsize = *((size_t*)realptr);
     203                 :     update_zmalloc_stat_free(oldsize+PREFIX_SIZE);
     204                 :     free(realptr);
     205                 : #endif
     206                 : }
     207                 : 
     208             440 : char *zstrdup(const char *s) {
     209             440 :     size_t l = strlen(s)+1;
     210             440 :     char *p = zmalloc(l);
     211                 : 
     212                 :     memcpy(p,s,l);
     213             440 :     return p;
     214                 : }
     215                 : 
     216           71262 : size_t zmalloc_used_memory(void) {
     217                 :     size_t um;
     218                 : 
     219           71262 :     if (zmalloc_thread_safe) {
     220                 : #ifdef HAVE_ATOMIC
     221           71262 :         um = __sync_add_and_fetch(&used_memory, 0);
     222                 : #else
     223                 :         pthread_mutex_lock(&used_memory_mutex);
     224                 :         um = used_memory;
     225                 :         pthread_mutex_unlock(&used_memory_mutex);
     226                 : #endif
     227                 :     }
     228                 :     else {
     229               0 :         um = used_memory;
     230                 :     }
     231                 : 
     232           71262 :     return um;
     233                 : }
     234                 : 
     235              53 : void zmalloc_enable_thread_safeness(void) {
     236              53 :     zmalloc_thread_safe = 1;
     237              53 : }
     238                 : 
     239                 : /* Get the RSS information in an OS-specific way.
     240                 :  *
     241                 :  * WARNING: the function zmalloc_get_rss() is not designed to be fast
     242                 :  * and may not be called in the busy loops where Redis tries to release
     243                 :  * memory expiring or swapping out objects.
     244                 :  *
     245                 :  * For this kind of "fast RSS reporting" usages use instead the
     246                 :  * function RedisEstimateRSS() that is a much faster (and less precise)
     247                 :  * version of the funciton. */
     248                 : 
     249                 : #if defined(HAVE_PROCFS)
     250                 : #include <unistd.h>
     251                 : #include <sys/types.h>
     252                 : #include <sys/stat.h>
     253                 : #include <fcntl.h>
     254                 : 
     255           18336 : size_t zmalloc_get_rss(void) {
     256           18336 :     int page = sysconf(_SC_PAGESIZE);
     257                 :     size_t rss;
     258                 :     char buf[4096];
     259                 :     char filename[256];
     260                 :     int fd, count;
     261                 :     char *p, *x;
     262                 : 
     263           18336 :     snprintf(filename,256,"/proc/%d/stat",getpid());
     264           18336 :     if ((fd = open(filename,O_RDONLY)) == -1) return 0;
     265           18336 :     if (read(fd,buf,4096) <= 0) {
     266               0 :         close(fd);
     267               0 :         return 0;
     268                 :     }
     269           18336 :     close(fd);
     270                 : 
     271           18336 :     p = buf;
     272           18336 :     count = 23; /* RSS is the 24th field in /proc/<pid>/stat */
     273          458400 :     while(p && count--) {
     274          421728 :         p = strchr(p,' ');
     275          421728 :         if (p) p++;
     276                 :     }
     277           18336 :     if (!p) return 0;
     278           18336 :     x = strchr(p,' ');
     279           18336 :     if (!x) return 0;
     280           18336 :     *x = '\0';
     281                 : 
     282           18336 :     rss = strtoll(p,NULL,10);
     283           18336 :     rss *= page;
     284           18336 :     return rss;
     285                 : }
     286                 : #elif defined(HAVE_TASKINFO)
     287                 : #include <unistd.h>
     288                 : #include <stdio.h>
     289                 : #include <stdlib.h>
     290                 : #include <sys/types.h>
     291                 : #include <sys/sysctl.h>
     292                 : #include <mach/task.h>
     293                 : #include <mach/mach_init.h>
     294                 : 
     295                 : size_t zmalloc_get_rss(void) {
     296                 :     task_t task = MACH_PORT_NULL;
     297                 :     struct task_basic_info t_info;
     298                 :     mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
     299                 : 
     300                 :     if (task_for_pid(current_task(), getpid(), &task) != KERN_SUCCESS)
     301                 :         return 0;
     302                 :     task_info(task, TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count);
     303                 : 
     304                 :     return t_info.resident_size;
     305                 : }
     306                 : #else
     307                 : size_t zmalloc_get_rss(void) {
     308                 :     /* If we can't get the RSS in an OS-specific way for this system just
     309                 :      * return the memory usage we estimated in zmalloc()..
     310                 :      *
     311                 :      * Fragmentation will appear to be always 1 (no fragmentation)
     312                 :      * of course... */
     313                 :     return zmalloc_used_memory();
     314                 : }
     315                 : #endif
     316                 : 
     317                 : /* Fragmentation = RSS / allocated-bytes */
     318            9168 : float zmalloc_get_fragmentation_ratio(void) {
     319            9168 :     return (float)zmalloc_get_rss()/zmalloc_used_memory();
     320                 : }

Generated by: LCOV version 1.7