zmalloc.c 5.9 KB
Newer Older
A
antirez 已提交
1 2
/* zmalloc - total amount of allocated memory aware version of malloc()
 *
3
 * Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
A
antirez 已提交
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
 * 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 Redis 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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
 */

31
#include <stdio.h>
A
antirez 已提交
32 33
#include <stdlib.h>
#include <string.h>
34
#include <pthread.h>
35 36 37 38
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
39
#include "config.h"
40

41 42 43 44 45 46
#if defined(__sun)
#define PREFIX_SIZE sizeof(long long)
#else
#define PREFIX_SIZE sizeof(size_t)
#endif

47 48 49
#define increment_used_memory(__n) do { \
    size_t _n = (__n); \
    if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
50 51 52 53 54 55 56 57 58
    if (zmalloc_thread_safe) { \
        pthread_mutex_lock(&used_memory_mutex);  \
        used_memory += _n; \
        pthread_mutex_unlock(&used_memory_mutex); \
    } else { \
        used_memory += _n; \
    } \
} while(0)

59 60 61
#define decrement_used_memory(__n) do { \
    size_t _n = (__n); \
    if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
62 63 64 65 66 67 68 69 70
    if (zmalloc_thread_safe) { \
        pthread_mutex_lock(&used_memory_mutex);  \
        used_memory -= _n; \
        pthread_mutex_unlock(&used_memory_mutex); \
    } else { \
        used_memory -= _n; \
    } \
} while(0)

A
antirez 已提交
71
static size_t used_memory = 0;
72
static int zmalloc_thread_safe = 0;
73
pthread_mutex_t used_memory_mutex = PTHREAD_MUTEX_INITIALIZER;
A
antirez 已提交
74

75
static void zmalloc_oom(size_t size) {
76
    fprintf(stderr, "zmalloc: Out of memory trying to allocate %zu bytes\n",
77 78 79 80 81
        size);
    fflush(stderr);
    abort();
}

A
antirez 已提交
82
void *zmalloc(size_t size) {
83
    void *ptr = malloc(size+PREFIX_SIZE);
A
antirez 已提交
84

85
    if (!ptr) zmalloc_oom(size);
86
#ifdef HAVE_MALLOC_SIZE
87
    increment_used_memory(redis_malloc_size(ptr));
88 89
    return ptr;
#else
A
antirez 已提交
90
    *((size_t*)ptr) = size;
91
    increment_used_memory(size+PREFIX_SIZE);
92
    return (char*)ptr+PREFIX_SIZE;
93
#endif
A
antirez 已提交
94 95
}

96 97 98 99 100 101 102 103 104 105 106 107 108 109
void *zcalloc(size_t size) {
    void *ptr = calloc(1, size+PREFIX_SIZE);

    if (!ptr) zmalloc_oom(size);
#ifdef HAVE_MALLOC_SIZE
    increment_used_memory(redis_malloc_size(ptr));
    return ptr;
#else
    *((size_t*)ptr) = size;
    increment_used_memory(size+PREFIX_SIZE);
    return (char*)ptr+PREFIX_SIZE;
#endif
}

A
antirez 已提交
110
void *zrealloc(void *ptr, size_t size) {
111
#ifndef HAVE_MALLOC_SIZE
A
antirez 已提交
112
    void *realptr;
113
#endif
A
antirez 已提交
114 115 116 117
    size_t oldsize;
    void *newptr;

    if (ptr == NULL) return zmalloc(size);
118 119 120
#ifdef HAVE_MALLOC_SIZE
    oldsize = redis_malloc_size(ptr);
    newptr = realloc(ptr,size);
121
    if (!newptr) zmalloc_oom(size);
122

123 124
    decrement_used_memory(oldsize);
    increment_used_memory(redis_malloc_size(newptr));
125 126
    return newptr;
#else
127
    realptr = (char*)ptr-PREFIX_SIZE;
A
antirez 已提交
128
    oldsize = *((size_t*)realptr);
129
    newptr = realloc(realptr,size+PREFIX_SIZE);
130
    if (!newptr) zmalloc_oom(size);
A
antirez 已提交
131 132

    *((size_t*)newptr) = size;
133 134
    decrement_used_memory(oldsize);
    increment_used_memory(size);
135
    return (char*)newptr+PREFIX_SIZE;
136
#endif
A
antirez 已提交
137 138 139
}

void zfree(void *ptr) {
140
#ifndef HAVE_MALLOC_SIZE
A
antirez 已提交
141 142
    void *realptr;
    size_t oldsize;
143
#endif
A
antirez 已提交
144 145

    if (ptr == NULL) return;
146
#ifdef HAVE_MALLOC_SIZE
147
    decrement_used_memory(redis_malloc_size(ptr));
148 149
    free(ptr);
#else
150
    realptr = (char*)ptr-PREFIX_SIZE;
A
antirez 已提交
151
    oldsize = *((size_t*)realptr);
152
    decrement_used_memory(oldsize+PREFIX_SIZE);
A
antirez 已提交
153
    free(realptr);
154
#endif
A
antirez 已提交
155 156 157 158 159 160 161 162 163 164 165
}

char *zstrdup(const char *s) {
    size_t l = strlen(s)+1;
    char *p = zmalloc(l);

    memcpy(p,s,l);
    return p;
}

size_t zmalloc_used_memory(void) {
166 167 168 169 170 171 172 173 174 175
    size_t um;

    if (zmalloc_thread_safe) pthread_mutex_lock(&used_memory_mutex);
    um = used_memory;
    if (zmalloc_thread_safe) pthread_mutex_unlock(&used_memory_mutex);
    return um;
}

void zmalloc_enable_thread_safeness(void) {
    zmalloc_thread_safe = 1;
A
antirez 已提交
176
}
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214

/* Fragmentation = RSS / allocated-bytes */
float zmalloc_get_fragmentation_ratio(void) {
#ifdef HAVE_PROCFS
    size_t allocated = zmalloc_used_memory();
    int page = sysconf(_SC_PAGESIZE);
    size_t rss;
    char buf[4096];
    char filename[256];
    int fd, count;
    char *p, *x;

    snprintf(filename,256,"/proc/%d/stat",getpid());
    if ((fd = open(filename,O_RDONLY)) == -1) return 0;
    if (read(fd,buf,4096) <= 0) {
        close(fd);
        return 0;
    }
    close(fd);

    p = buf;
    count = 23; /* RSS is the 24th field in /proc/<pid>/stat */
    while(p && count--) {
        p = strchr(p,' ');
        if (p) p++;
    }
    if (!p) return 0;
    x = strchr(p,' ');
    if (!x) return 0;
    *x = '\0';

    rss = strtoll(p,NULL,10);
    rss *= page;
    return (float)rss/allocated;
#else
    return 0;
#endif
}