xref: /f-stack/app/redis-5.0.5/src/zmalloc.c (revision 572c4311)
1*572c4311Sfengbojiang /* zmalloc - total amount of allocated memory aware version of malloc()
2*572c4311Sfengbojiang  *
3*572c4311Sfengbojiang  * Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
4*572c4311Sfengbojiang  * All rights reserved.
5*572c4311Sfengbojiang  *
6*572c4311Sfengbojiang  * Redistribution and use in source and binary forms, with or without
7*572c4311Sfengbojiang  * modification, are permitted provided that the following conditions are met:
8*572c4311Sfengbojiang  *
9*572c4311Sfengbojiang  *   * Redistributions of source code must retain the above copyright notice,
10*572c4311Sfengbojiang  *     this list of conditions and the following disclaimer.
11*572c4311Sfengbojiang  *   * Redistributions in binary form must reproduce the above copyright
12*572c4311Sfengbojiang  *     notice, this list of conditions and the following disclaimer in the
13*572c4311Sfengbojiang  *     documentation and/or other materials provided with the distribution.
14*572c4311Sfengbojiang  *   * Neither the name of Redis nor the names of its contributors may be used
15*572c4311Sfengbojiang  *     to endorse or promote products derived from this software without
16*572c4311Sfengbojiang  *     specific prior written permission.
17*572c4311Sfengbojiang  *
18*572c4311Sfengbojiang  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19*572c4311Sfengbojiang  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*572c4311Sfengbojiang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*572c4311Sfengbojiang  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22*572c4311Sfengbojiang  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23*572c4311Sfengbojiang  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24*572c4311Sfengbojiang  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25*572c4311Sfengbojiang  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26*572c4311Sfengbojiang  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27*572c4311Sfengbojiang  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28*572c4311Sfengbojiang  * POSSIBILITY OF SUCH DAMAGE.
29*572c4311Sfengbojiang  */
30*572c4311Sfengbojiang 
31*572c4311Sfengbojiang #include <stdio.h>
32*572c4311Sfengbojiang #include <stdlib.h>
33*572c4311Sfengbojiang #include <stdint.h>
34*572c4311Sfengbojiang 
35*572c4311Sfengbojiang /* This function provide us access to the original libc free(). This is useful
36*572c4311Sfengbojiang  * for instance to free results obtained by backtrace_symbols(). We need
37*572c4311Sfengbojiang  * to define this function before including zmalloc.h that may shadow the
38*572c4311Sfengbojiang  * free implementation if we use jemalloc or another non standard allocator. */
zlibc_free(void * ptr)39*572c4311Sfengbojiang void zlibc_free(void *ptr) {
40*572c4311Sfengbojiang     free(ptr);
41*572c4311Sfengbojiang }
42*572c4311Sfengbojiang 
43*572c4311Sfengbojiang #include <string.h>
44*572c4311Sfengbojiang #include <pthread.h>
45*572c4311Sfengbojiang #include "config.h"
46*572c4311Sfengbojiang #include "zmalloc.h"
47*572c4311Sfengbojiang #include "atomicvar.h"
48*572c4311Sfengbojiang 
49*572c4311Sfengbojiang #ifdef HAVE_MALLOC_SIZE
50*572c4311Sfengbojiang #define PREFIX_SIZE (0)
51*572c4311Sfengbojiang #else
52*572c4311Sfengbojiang #if defined(__sun) || defined(__sparc) || defined(__sparc__)
53*572c4311Sfengbojiang #define PREFIX_SIZE (sizeof(long long))
54*572c4311Sfengbojiang #else
55*572c4311Sfengbojiang #define PREFIX_SIZE (sizeof(size_t))
56*572c4311Sfengbojiang #endif
57*572c4311Sfengbojiang #endif
58*572c4311Sfengbojiang 
59*572c4311Sfengbojiang /* Explicitly override malloc/free etc when using tcmalloc. */
60*572c4311Sfengbojiang #if defined(USE_TCMALLOC)
61*572c4311Sfengbojiang #define malloc(size) tc_malloc(size)
62*572c4311Sfengbojiang #define calloc(count,size) tc_calloc(count,size)
63*572c4311Sfengbojiang #define realloc(ptr,size) tc_realloc(ptr,size)
64*572c4311Sfengbojiang #define free(ptr) tc_free(ptr)
65*572c4311Sfengbojiang #elif defined(USE_JEMALLOC)
66*572c4311Sfengbojiang #define malloc(size) je_malloc(size)
67*572c4311Sfengbojiang #define calloc(count,size) je_calloc(count,size)
68*572c4311Sfengbojiang #define realloc(ptr,size) je_realloc(ptr,size)
69*572c4311Sfengbojiang #define free(ptr) je_free(ptr)
70*572c4311Sfengbojiang #define mallocx(size,flags) je_mallocx(size,flags)
71*572c4311Sfengbojiang #define dallocx(ptr,flags) je_dallocx(ptr,flags)
72*572c4311Sfengbojiang #endif
73*572c4311Sfengbojiang 
74*572c4311Sfengbojiang #define update_zmalloc_stat_alloc(__n) do { \
75*572c4311Sfengbojiang     size_t _n = (__n); \
76*572c4311Sfengbojiang     if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
77*572c4311Sfengbojiang     atomicIncr(used_memory,__n); \
78*572c4311Sfengbojiang } while(0)
79*572c4311Sfengbojiang 
80*572c4311Sfengbojiang #define update_zmalloc_stat_free(__n) do { \
81*572c4311Sfengbojiang     size_t _n = (__n); \
82*572c4311Sfengbojiang     if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
83*572c4311Sfengbojiang     atomicDecr(used_memory,__n); \
84*572c4311Sfengbojiang } while(0)
85*572c4311Sfengbojiang 
86*572c4311Sfengbojiang static size_t used_memory = 0;
87*572c4311Sfengbojiang pthread_mutex_t used_memory_mutex = PTHREAD_MUTEX_INITIALIZER;
88*572c4311Sfengbojiang 
zmalloc_default_oom(size_t size)89*572c4311Sfengbojiang static void zmalloc_default_oom(size_t size) {
90*572c4311Sfengbojiang     fprintf(stderr, "zmalloc: Out of memory trying to allocate %zu bytes\n",
91*572c4311Sfengbojiang         size);
92*572c4311Sfengbojiang     fflush(stderr);
93*572c4311Sfengbojiang     abort();
94*572c4311Sfengbojiang }
95*572c4311Sfengbojiang 
96*572c4311Sfengbojiang static void (*zmalloc_oom_handler)(size_t) = zmalloc_default_oom;
97*572c4311Sfengbojiang 
zmalloc(size_t size)98*572c4311Sfengbojiang void *zmalloc(size_t size) {
99*572c4311Sfengbojiang     void *ptr = malloc(size+PREFIX_SIZE);
100*572c4311Sfengbojiang 
101*572c4311Sfengbojiang     if (!ptr) zmalloc_oom_handler(size);
102*572c4311Sfengbojiang #ifdef HAVE_MALLOC_SIZE
103*572c4311Sfengbojiang     update_zmalloc_stat_alloc(zmalloc_size(ptr));
104*572c4311Sfengbojiang     return ptr;
105*572c4311Sfengbojiang #else
106*572c4311Sfengbojiang     *((size_t*)ptr) = size;
107*572c4311Sfengbojiang     update_zmalloc_stat_alloc(size+PREFIX_SIZE);
108*572c4311Sfengbojiang     return (char*)ptr+PREFIX_SIZE;
109*572c4311Sfengbojiang #endif
110*572c4311Sfengbojiang }
111*572c4311Sfengbojiang 
112*572c4311Sfengbojiang /* Allocation and free functions that bypass the thread cache
113*572c4311Sfengbojiang  * and go straight to the allocator arena bins.
114*572c4311Sfengbojiang  * Currently implemented only for jemalloc. Used for online defragmentation. */
115*572c4311Sfengbojiang #ifdef HAVE_DEFRAG
zmalloc_no_tcache(size_t size)116*572c4311Sfengbojiang void *zmalloc_no_tcache(size_t size) {
117*572c4311Sfengbojiang     void *ptr = mallocx(size+PREFIX_SIZE, MALLOCX_TCACHE_NONE);
118*572c4311Sfengbojiang     if (!ptr) zmalloc_oom_handler(size);
119*572c4311Sfengbojiang     update_zmalloc_stat_alloc(zmalloc_size(ptr));
120*572c4311Sfengbojiang     return ptr;
121*572c4311Sfengbojiang }
122*572c4311Sfengbojiang 
zfree_no_tcache(void * ptr)123*572c4311Sfengbojiang void zfree_no_tcache(void *ptr) {
124*572c4311Sfengbojiang     if (ptr == NULL) return;
125*572c4311Sfengbojiang     update_zmalloc_stat_free(zmalloc_size(ptr));
126*572c4311Sfengbojiang     dallocx(ptr, MALLOCX_TCACHE_NONE);
127*572c4311Sfengbojiang }
128*572c4311Sfengbojiang #endif
129*572c4311Sfengbojiang 
zcalloc(size_t size)130*572c4311Sfengbojiang void *zcalloc(size_t size) {
131*572c4311Sfengbojiang     void *ptr = calloc(1, size+PREFIX_SIZE);
132*572c4311Sfengbojiang 
133*572c4311Sfengbojiang     if (!ptr) zmalloc_oom_handler(size);
134*572c4311Sfengbojiang #ifdef HAVE_MALLOC_SIZE
135*572c4311Sfengbojiang     update_zmalloc_stat_alloc(zmalloc_size(ptr));
136*572c4311Sfengbojiang     return ptr;
137*572c4311Sfengbojiang #else
138*572c4311Sfengbojiang     *((size_t*)ptr) = size;
139*572c4311Sfengbojiang     update_zmalloc_stat_alloc(size+PREFIX_SIZE);
140*572c4311Sfengbojiang     return (char*)ptr+PREFIX_SIZE;
141*572c4311Sfengbojiang #endif
142*572c4311Sfengbojiang }
143*572c4311Sfengbojiang 
zrealloc(void * ptr,size_t size)144*572c4311Sfengbojiang void *zrealloc(void *ptr, size_t size) {
145*572c4311Sfengbojiang #ifndef HAVE_MALLOC_SIZE
146*572c4311Sfengbojiang     void *realptr;
147*572c4311Sfengbojiang #endif
148*572c4311Sfengbojiang     size_t oldsize;
149*572c4311Sfengbojiang     void *newptr;
150*572c4311Sfengbojiang 
151*572c4311Sfengbojiang     if (ptr == NULL) return zmalloc(size);
152*572c4311Sfengbojiang #ifdef HAVE_MALLOC_SIZE
153*572c4311Sfengbojiang     oldsize = zmalloc_size(ptr);
154*572c4311Sfengbojiang     newptr = realloc(ptr,size);
155*572c4311Sfengbojiang     if (!newptr) zmalloc_oom_handler(size);
156*572c4311Sfengbojiang 
157*572c4311Sfengbojiang     update_zmalloc_stat_free(oldsize);
158*572c4311Sfengbojiang     update_zmalloc_stat_alloc(zmalloc_size(newptr));
159*572c4311Sfengbojiang     return newptr;
160*572c4311Sfengbojiang #else
161*572c4311Sfengbojiang     realptr = (char*)ptr-PREFIX_SIZE;
162*572c4311Sfengbojiang     oldsize = *((size_t*)realptr);
163*572c4311Sfengbojiang     newptr = realloc(realptr,size+PREFIX_SIZE);
164*572c4311Sfengbojiang     if (!newptr) zmalloc_oom_handler(size);
165*572c4311Sfengbojiang 
166*572c4311Sfengbojiang     *((size_t*)newptr) = size;
167*572c4311Sfengbojiang     update_zmalloc_stat_free(oldsize+PREFIX_SIZE);
168*572c4311Sfengbojiang     update_zmalloc_stat_alloc(size+PREFIX_SIZE);
169*572c4311Sfengbojiang     return (char*)newptr+PREFIX_SIZE;
170*572c4311Sfengbojiang #endif
171*572c4311Sfengbojiang }
172*572c4311Sfengbojiang 
173*572c4311Sfengbojiang /* Provide zmalloc_size() for systems where this function is not provided by
174*572c4311Sfengbojiang  * malloc itself, given that in that case we store a header with this
175*572c4311Sfengbojiang  * information as the first bytes of every allocation. */
176*572c4311Sfengbojiang #ifndef HAVE_MALLOC_SIZE
zmalloc_size(void * ptr)177*572c4311Sfengbojiang size_t zmalloc_size(void *ptr) {
178*572c4311Sfengbojiang     void *realptr = (char*)ptr-PREFIX_SIZE;
179*572c4311Sfengbojiang     size_t size = *((size_t*)realptr);
180*572c4311Sfengbojiang     /* Assume at least that all the allocations are padded at sizeof(long) by
181*572c4311Sfengbojiang      * the underlying allocator. */
182*572c4311Sfengbojiang     if (size&(sizeof(long)-1)) size += sizeof(long)-(size&(sizeof(long)-1));
183*572c4311Sfengbojiang     return size+PREFIX_SIZE;
184*572c4311Sfengbojiang }
zmalloc_usable(void * ptr)185*572c4311Sfengbojiang size_t zmalloc_usable(void *ptr) {
186*572c4311Sfengbojiang     return zmalloc_size(ptr)-PREFIX_SIZE;
187*572c4311Sfengbojiang }
188*572c4311Sfengbojiang #endif
189*572c4311Sfengbojiang 
zfree(void * ptr)190*572c4311Sfengbojiang void zfree(void *ptr) {
191*572c4311Sfengbojiang #ifndef HAVE_MALLOC_SIZE
192*572c4311Sfengbojiang     void *realptr;
193*572c4311Sfengbojiang     size_t oldsize;
194*572c4311Sfengbojiang #endif
195*572c4311Sfengbojiang 
196*572c4311Sfengbojiang     if (ptr == NULL) return;
197*572c4311Sfengbojiang #ifdef HAVE_MALLOC_SIZE
198*572c4311Sfengbojiang     update_zmalloc_stat_free(zmalloc_size(ptr));
199*572c4311Sfengbojiang     free(ptr);
200*572c4311Sfengbojiang #else
201*572c4311Sfengbojiang     realptr = (char*)ptr-PREFIX_SIZE;
202*572c4311Sfengbojiang     oldsize = *((size_t*)realptr);
203*572c4311Sfengbojiang     update_zmalloc_stat_free(oldsize+PREFIX_SIZE);
204*572c4311Sfengbojiang     free(realptr);
205*572c4311Sfengbojiang #endif
206*572c4311Sfengbojiang }
207*572c4311Sfengbojiang 
zstrdup(const char * s)208*572c4311Sfengbojiang char *zstrdup(const char *s) {
209*572c4311Sfengbojiang     size_t l = strlen(s)+1;
210*572c4311Sfengbojiang     char *p = zmalloc(l);
211*572c4311Sfengbojiang 
212*572c4311Sfengbojiang     memcpy(p,s,l);
213*572c4311Sfengbojiang     return p;
214*572c4311Sfengbojiang }
215*572c4311Sfengbojiang 
zmalloc_used_memory(void)216*572c4311Sfengbojiang size_t zmalloc_used_memory(void) {
217*572c4311Sfengbojiang     size_t um;
218*572c4311Sfengbojiang     atomicGet(used_memory,um);
219*572c4311Sfengbojiang     return um;
220*572c4311Sfengbojiang }
221*572c4311Sfengbojiang 
zmalloc_set_oom_handler(void (* oom_handler)(size_t))222*572c4311Sfengbojiang void zmalloc_set_oom_handler(void (*oom_handler)(size_t)) {
223*572c4311Sfengbojiang     zmalloc_oom_handler = oom_handler;
224*572c4311Sfengbojiang }
225*572c4311Sfengbojiang 
226*572c4311Sfengbojiang /* Get the RSS information in an OS-specific way.
227*572c4311Sfengbojiang  *
228*572c4311Sfengbojiang  * WARNING: the function zmalloc_get_rss() is not designed to be fast
229*572c4311Sfengbojiang  * and may not be called in the busy loops where Redis tries to release
230*572c4311Sfengbojiang  * memory expiring or swapping out objects.
231*572c4311Sfengbojiang  *
232*572c4311Sfengbojiang  * For this kind of "fast RSS reporting" usages use instead the
233*572c4311Sfengbojiang  * function RedisEstimateRSS() that is a much faster (and less precise)
234*572c4311Sfengbojiang  * version of the function. */
235*572c4311Sfengbojiang 
236*572c4311Sfengbojiang #if defined(HAVE_PROC_STAT)
237*572c4311Sfengbojiang #include <unistd.h>
238*572c4311Sfengbojiang #include <sys/types.h>
239*572c4311Sfengbojiang #include <sys/stat.h>
240*572c4311Sfengbojiang #include <fcntl.h>
241*572c4311Sfengbojiang 
zmalloc_get_rss(void)242*572c4311Sfengbojiang size_t zmalloc_get_rss(void) {
243*572c4311Sfengbojiang     int page = sysconf(_SC_PAGESIZE);
244*572c4311Sfengbojiang     size_t rss;
245*572c4311Sfengbojiang     char buf[4096];
246*572c4311Sfengbojiang     char filename[256];
247*572c4311Sfengbojiang     int fd, count;
248*572c4311Sfengbojiang     char *p, *x;
249*572c4311Sfengbojiang 
250*572c4311Sfengbojiang     snprintf(filename,256,"/proc/%d/stat",getpid());
251*572c4311Sfengbojiang     if ((fd = open(filename,O_RDONLY)) == -1) return 0;
252*572c4311Sfengbojiang     if (read(fd,buf,4096) <= 0) {
253*572c4311Sfengbojiang         close(fd);
254*572c4311Sfengbojiang         return 0;
255*572c4311Sfengbojiang     }
256*572c4311Sfengbojiang     close(fd);
257*572c4311Sfengbojiang 
258*572c4311Sfengbojiang     p = buf;
259*572c4311Sfengbojiang     count = 23; /* RSS is the 24th field in /proc/<pid>/stat */
260*572c4311Sfengbojiang     while(p && count--) {
261*572c4311Sfengbojiang         p = strchr(p,' ');
262*572c4311Sfengbojiang         if (p) p++;
263*572c4311Sfengbojiang     }
264*572c4311Sfengbojiang     if (!p) return 0;
265*572c4311Sfengbojiang     x = strchr(p,' ');
266*572c4311Sfengbojiang     if (!x) return 0;
267*572c4311Sfengbojiang     *x = '\0';
268*572c4311Sfengbojiang 
269*572c4311Sfengbojiang     rss = strtoll(p,NULL,10);
270*572c4311Sfengbojiang     rss *= page;
271*572c4311Sfengbojiang     return rss;
272*572c4311Sfengbojiang }
273*572c4311Sfengbojiang #elif defined(HAVE_TASKINFO)
274*572c4311Sfengbojiang #include <unistd.h>
275*572c4311Sfengbojiang #include <stdio.h>
276*572c4311Sfengbojiang #include <stdlib.h>
277*572c4311Sfengbojiang #include <sys/types.h>
278*572c4311Sfengbojiang #include <sys/sysctl.h>
279*572c4311Sfengbojiang #include <mach/task.h>
280*572c4311Sfengbojiang #include <mach/mach_init.h>
281*572c4311Sfengbojiang 
zmalloc_get_rss(void)282*572c4311Sfengbojiang size_t zmalloc_get_rss(void) {
283*572c4311Sfengbojiang     task_t task = MACH_PORT_NULL;
284*572c4311Sfengbojiang     struct task_basic_info t_info;
285*572c4311Sfengbojiang     mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
286*572c4311Sfengbojiang 
287*572c4311Sfengbojiang     if (task_for_pid(current_task(), getpid(), &task) != KERN_SUCCESS)
288*572c4311Sfengbojiang         return 0;
289*572c4311Sfengbojiang     task_info(task, TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count);
290*572c4311Sfengbojiang 
291*572c4311Sfengbojiang     return t_info.resident_size;
292*572c4311Sfengbojiang }
293*572c4311Sfengbojiang #else
zmalloc_get_rss(void)294*572c4311Sfengbojiang size_t zmalloc_get_rss(void) {
295*572c4311Sfengbojiang     /* If we can't get the RSS in an OS-specific way for this system just
296*572c4311Sfengbojiang      * return the memory usage we estimated in zmalloc()..
297*572c4311Sfengbojiang      *
298*572c4311Sfengbojiang      * Fragmentation will appear to be always 1 (no fragmentation)
299*572c4311Sfengbojiang      * of course... */
300*572c4311Sfengbojiang     return zmalloc_used_memory();
301*572c4311Sfengbojiang }
302*572c4311Sfengbojiang #endif
303*572c4311Sfengbojiang 
304*572c4311Sfengbojiang #if defined(USE_JEMALLOC)
zmalloc_get_allocator_info(size_t * allocated,size_t * active,size_t * resident)305*572c4311Sfengbojiang int zmalloc_get_allocator_info(size_t *allocated,
306*572c4311Sfengbojiang                                size_t *active,
307*572c4311Sfengbojiang                                size_t *resident) {
308*572c4311Sfengbojiang     uint64_t epoch = 1;
309*572c4311Sfengbojiang     size_t sz;
310*572c4311Sfengbojiang     *allocated = *resident = *active = 0;
311*572c4311Sfengbojiang     /* Update the statistics cached by mallctl. */
312*572c4311Sfengbojiang     sz = sizeof(epoch);
313*572c4311Sfengbojiang     je_mallctl("epoch", &epoch, &sz, &epoch, sz);
314*572c4311Sfengbojiang     sz = sizeof(size_t);
315*572c4311Sfengbojiang     /* Unlike RSS, this does not include RSS from shared libraries and other non
316*572c4311Sfengbojiang      * heap mappings. */
317*572c4311Sfengbojiang     je_mallctl("stats.resident", resident, &sz, NULL, 0);
318*572c4311Sfengbojiang     /* Unlike resident, this doesn't not include the pages jemalloc reserves
319*572c4311Sfengbojiang      * for re-use (purge will clean that). */
320*572c4311Sfengbojiang     je_mallctl("stats.active", active, &sz, NULL, 0);
321*572c4311Sfengbojiang     /* Unlike zmalloc_used_memory, this matches the stats.resident by taking
322*572c4311Sfengbojiang      * into account all allocations done by this process (not only zmalloc). */
323*572c4311Sfengbojiang     je_mallctl("stats.allocated", allocated, &sz, NULL, 0);
324*572c4311Sfengbojiang     return 1;
325*572c4311Sfengbojiang }
326*572c4311Sfengbojiang #else
zmalloc_get_allocator_info(size_t * allocated,size_t * active,size_t * resident)327*572c4311Sfengbojiang int zmalloc_get_allocator_info(size_t *allocated,
328*572c4311Sfengbojiang                                size_t *active,
329*572c4311Sfengbojiang                                size_t *resident) {
330*572c4311Sfengbojiang     *allocated = *resident = *active = 0;
331*572c4311Sfengbojiang     return 1;
332*572c4311Sfengbojiang }
333*572c4311Sfengbojiang #endif
334*572c4311Sfengbojiang 
335*572c4311Sfengbojiang /* Get the sum of the specified field (converted form kb to bytes) in
336*572c4311Sfengbojiang  * /proc/self/smaps. The field must be specified with trailing ":" as it
337*572c4311Sfengbojiang  * apperas in the smaps output.
338*572c4311Sfengbojiang  *
339*572c4311Sfengbojiang  * If a pid is specified, the information is extracted for such a pid,
340*572c4311Sfengbojiang  * otherwise if pid is -1 the information is reported is about the
341*572c4311Sfengbojiang  * current process.
342*572c4311Sfengbojiang  *
343*572c4311Sfengbojiang  * Example: zmalloc_get_smap_bytes_by_field("Rss:",-1);
344*572c4311Sfengbojiang  */
345*572c4311Sfengbojiang #if defined(HAVE_PROC_SMAPS)
zmalloc_get_smap_bytes_by_field(char * field,long pid)346*572c4311Sfengbojiang size_t zmalloc_get_smap_bytes_by_field(char *field, long pid) {
347*572c4311Sfengbojiang     char line[1024];
348*572c4311Sfengbojiang     size_t bytes = 0;
349*572c4311Sfengbojiang     int flen = strlen(field);
350*572c4311Sfengbojiang     FILE *fp;
351*572c4311Sfengbojiang 
352*572c4311Sfengbojiang     if (pid == -1) {
353*572c4311Sfengbojiang         fp = fopen("/proc/self/smaps","r");
354*572c4311Sfengbojiang     } else {
355*572c4311Sfengbojiang         char filename[128];
356*572c4311Sfengbojiang         snprintf(filename,sizeof(filename),"/proc/%ld/smaps",pid);
357*572c4311Sfengbojiang         fp = fopen(filename,"r");
358*572c4311Sfengbojiang     }
359*572c4311Sfengbojiang 
360*572c4311Sfengbojiang     if (!fp) return 0;
361*572c4311Sfengbojiang     while(fgets(line,sizeof(line),fp) != NULL) {
362*572c4311Sfengbojiang         if (strncmp(line,field,flen) == 0) {
363*572c4311Sfengbojiang             char *p = strchr(line,'k');
364*572c4311Sfengbojiang             if (p) {
365*572c4311Sfengbojiang                 *p = '\0';
366*572c4311Sfengbojiang                 bytes += strtol(line+flen,NULL,10) * 1024;
367*572c4311Sfengbojiang             }
368*572c4311Sfengbojiang         }
369*572c4311Sfengbojiang     }
370*572c4311Sfengbojiang     fclose(fp);
371*572c4311Sfengbojiang     return bytes;
372*572c4311Sfengbojiang }
373*572c4311Sfengbojiang #else
zmalloc_get_smap_bytes_by_field(char * field,long pid)374*572c4311Sfengbojiang size_t zmalloc_get_smap_bytes_by_field(char *field, long pid) {
375*572c4311Sfengbojiang     ((void) field);
376*572c4311Sfengbojiang     ((void) pid);
377*572c4311Sfengbojiang     return 0;
378*572c4311Sfengbojiang }
379*572c4311Sfengbojiang #endif
380*572c4311Sfengbojiang 
zmalloc_get_private_dirty(long pid)381*572c4311Sfengbojiang size_t zmalloc_get_private_dirty(long pid) {
382*572c4311Sfengbojiang     return zmalloc_get_smap_bytes_by_field("Private_Dirty:",pid);
383*572c4311Sfengbojiang }
384*572c4311Sfengbojiang 
385*572c4311Sfengbojiang /* Returns the size of physical memory (RAM) in bytes.
386*572c4311Sfengbojiang  * It looks ugly, but this is the cleanest way to achieve cross platform results.
387*572c4311Sfengbojiang  * Cleaned up from:
388*572c4311Sfengbojiang  *
389*572c4311Sfengbojiang  * http://nadeausoftware.com/articles/2012/09/c_c_tip_how_get_physical_memory_size_system
390*572c4311Sfengbojiang  *
391*572c4311Sfengbojiang  * Note that this function:
392*572c4311Sfengbojiang  * 1) Was released under the following CC attribution license:
393*572c4311Sfengbojiang  *    http://creativecommons.org/licenses/by/3.0/deed.en_US.
394*572c4311Sfengbojiang  * 2) Was originally implemented by David Robert Nadeau.
395*572c4311Sfengbojiang  * 3) Was modified for Redis by Matt Stancliff.
396*572c4311Sfengbojiang  * 4) This note exists in order to comply with the original license.
397*572c4311Sfengbojiang  */
zmalloc_get_memory_size(void)398*572c4311Sfengbojiang size_t zmalloc_get_memory_size(void) {
399*572c4311Sfengbojiang #if defined(__unix__) || defined(__unix) || defined(unix) || \
400*572c4311Sfengbojiang     (defined(__APPLE__) && defined(__MACH__))
401*572c4311Sfengbojiang #if defined(CTL_HW) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64))
402*572c4311Sfengbojiang     int mib[2];
403*572c4311Sfengbojiang     mib[0] = CTL_HW;
404*572c4311Sfengbojiang #if defined(HW_MEMSIZE)
405*572c4311Sfengbojiang     mib[1] = HW_MEMSIZE;            /* OSX. --------------------- */
406*572c4311Sfengbojiang #elif defined(HW_PHYSMEM64)
407*572c4311Sfengbojiang     mib[1] = HW_PHYSMEM64;          /* NetBSD, OpenBSD. --------- */
408*572c4311Sfengbojiang #endif
409*572c4311Sfengbojiang     int64_t size = 0;               /* 64-bit */
410*572c4311Sfengbojiang     size_t len = sizeof(size);
411*572c4311Sfengbojiang     if (sysctl( mib, 2, &size, &len, NULL, 0) == 0)
412*572c4311Sfengbojiang         return (size_t)size;
413*572c4311Sfengbojiang     return 0L;          /* Failed? */
414*572c4311Sfengbojiang 
415*572c4311Sfengbojiang #elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
416*572c4311Sfengbojiang     /* FreeBSD, Linux, OpenBSD, and Solaris. -------------------- */
417*572c4311Sfengbojiang     return (size_t)sysconf(_SC_PHYS_PAGES) * (size_t)sysconf(_SC_PAGESIZE);
418*572c4311Sfengbojiang 
419*572c4311Sfengbojiang #elif defined(CTL_HW) && (defined(HW_PHYSMEM) || defined(HW_REALMEM))
420*572c4311Sfengbojiang     /* DragonFly BSD, FreeBSD, NetBSD, OpenBSD, and OSX. -------- */
421*572c4311Sfengbojiang     int mib[2];
422*572c4311Sfengbojiang     mib[0] = CTL_HW;
423*572c4311Sfengbojiang #if defined(HW_REALMEM)
424*572c4311Sfengbojiang     mib[1] = HW_REALMEM;        /* FreeBSD. ----------------- */
425*572c4311Sfengbojiang #elif defined(HW_PHYSMEM)
426*572c4311Sfengbojiang     mib[1] = HW_PHYSMEM;        /* Others. ------------------ */
427*572c4311Sfengbojiang #endif
428*572c4311Sfengbojiang     unsigned int size = 0;      /* 32-bit */
429*572c4311Sfengbojiang     size_t len = sizeof(size);
430*572c4311Sfengbojiang     if (sysctl(mib, 2, &size, &len, NULL, 0) == 0)
431*572c4311Sfengbojiang         return (size_t)size;
432*572c4311Sfengbojiang     return 0L;          /* Failed? */
433*572c4311Sfengbojiang #else
434*572c4311Sfengbojiang     return 0L;          /* Unknown method to get the data. */
435*572c4311Sfengbojiang #endif
436*572c4311Sfengbojiang #else
437*572c4311Sfengbojiang     return 0L;          /* Unknown OS. */
438*572c4311Sfengbojiang #endif
439*572c4311Sfengbojiang }
440*572c4311Sfengbojiang 
441*572c4311Sfengbojiang #ifdef REDIS_TEST
442*572c4311Sfengbojiang #define UNUSED(x) ((void)(x))
zmalloc_test(int argc,char ** argv)443*572c4311Sfengbojiang int zmalloc_test(int argc, char **argv) {
444*572c4311Sfengbojiang     void *ptr;
445*572c4311Sfengbojiang 
446*572c4311Sfengbojiang     UNUSED(argc);
447*572c4311Sfengbojiang     UNUSED(argv);
448*572c4311Sfengbojiang     printf("Initial used memory: %zu\n", zmalloc_used_memory());
449*572c4311Sfengbojiang     ptr = zmalloc(123);
450*572c4311Sfengbojiang     printf("Allocated 123 bytes; used: %zu\n", zmalloc_used_memory());
451*572c4311Sfengbojiang     ptr = zrealloc(ptr, 456);
452*572c4311Sfengbojiang     printf("Reallocated to 456 bytes; used: %zu\n", zmalloc_used_memory());
453*572c4311Sfengbojiang     zfree(ptr);
454*572c4311Sfengbojiang     printf("Freed pointer; used: %zu\n", zmalloc_used_memory());
455*572c4311Sfengbojiang     return 0;
456*572c4311Sfengbojiang }
457*572c4311Sfengbojiang #endif
458