"Fossies" - the Fresh Open Source Software Archive 
Member "wrk-4.2.0/src/zmalloc.c" (7 Feb 2021, 12629 Bytes) of package /linux/www/wrk-4.2.0.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "zmalloc.c" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
4.0.2_vs_4.1.0.
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 void zlibc_free(void *ptr) {
39 free(ptr);
40 }
41
42 #include <string.h>
43 #include <pthread.h>
44 #include "config.h"
45 #include "zmalloc.h"
46 #include "atomicvar.h"
47
48 #ifdef HAVE_MALLOC_SIZE
49 #define PREFIX_SIZE (0)
50 #else
51 #if defined(__sun) || defined(__sparc) || defined(__sparc__)
52 #define PREFIX_SIZE (sizeof(long long))
53 #else
54 #define PREFIX_SIZE (sizeof(size_t))
55 #endif
56 #endif
57
58 /* Explicitly override malloc/free etc when using tcmalloc. */
59 #if defined(USE_TCMALLOC)
60 #define malloc(size) tc_malloc(size)
61 #define calloc(count,size) tc_calloc(count,size)
62 #define realloc(ptr,size) tc_realloc(ptr,size)
63 #define free(ptr) tc_free(ptr)
64 #elif defined(USE_JEMALLOC)
65 #define malloc(size) je_malloc(size)
66 #define calloc(count,size) je_calloc(count,size)
67 #define realloc(ptr,size) je_realloc(ptr,size)
68 #define free(ptr) je_free(ptr)
69 #define mallocx(size,flags) je_mallocx(size,flags)
70 #define dallocx(ptr,flags) je_dallocx(ptr,flags)
71 #endif
72
73 #define update_zmalloc_stat_alloc(__n) do { \
74 size_t _n = (__n); \
75 if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
76 atomicIncr(used_memory,__n); \
77 } while(0)
78
79 #define update_zmalloc_stat_free(__n) do { \
80 size_t _n = (__n); \
81 if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
82 atomicDecr(used_memory,__n); \
83 } while(0)
84
85 static size_t used_memory = 0;
86 pthread_mutex_t used_memory_mutex = PTHREAD_MUTEX_INITIALIZER;
87
88 static void zmalloc_default_oom(size_t size) {
89 fprintf(stderr, "zmalloc: Out of memory trying to allocate %zu bytes\n",
90 size);
91 fflush(stderr);
92 abort();
93 }
94
95 static void (*zmalloc_oom_handler)(size_t) = zmalloc_default_oom;
96
97 void *zmalloc(size_t size) {
98 void *ptr = malloc(size+PREFIX_SIZE);
99
100 if (!ptr) zmalloc_oom_handler(size);
101 #ifdef HAVE_MALLOC_SIZE
102 update_zmalloc_stat_alloc(zmalloc_size(ptr));
103 return ptr;
104 #else
105 *((size_t*)ptr) = size;
106 update_zmalloc_stat_alloc(size+PREFIX_SIZE);
107 return (char*)ptr+PREFIX_SIZE;
108 #endif
109 }
110
111 /* Allocation and free functions that bypass the thread cache
112 * and go straight to the allocator arena bins.
113 * Currently implemented only for jemalloc. Used for online defragmentation. */
114 #ifdef HAVE_DEFRAG
115 void *zmalloc_no_tcache(size_t size) {
116 void *ptr = mallocx(size+PREFIX_SIZE, MALLOCX_TCACHE_NONE);
117 if (!ptr) zmalloc_oom_handler(size);
118 update_zmalloc_stat_alloc(zmalloc_size(ptr));
119 return ptr;
120 }
121
122 void zfree_no_tcache(void *ptr) {
123 if (ptr == NULL) return;
124 update_zmalloc_stat_free(zmalloc_size(ptr));
125 dallocx(ptr, MALLOCX_TCACHE_NONE);
126 }
127 #endif
128
129 void *zcalloc(size_t size) {
130 void *ptr = calloc(1, size+PREFIX_SIZE);
131
132 if (!ptr) zmalloc_oom_handler(size);
133 #ifdef HAVE_MALLOC_SIZE
134 update_zmalloc_stat_alloc(zmalloc_size(ptr));
135 return ptr;
136 #else
137 *((size_t*)ptr) = size;
138 update_zmalloc_stat_alloc(size+PREFIX_SIZE);
139 return (char*)ptr+PREFIX_SIZE;
140 #endif
141 }
142
143 void *zrealloc(void *ptr, size_t size) {
144 #ifndef HAVE_MALLOC_SIZE
145 void *realptr;
146 #endif
147 size_t oldsize;
148 void *newptr;
149
150 if (ptr == NULL) return zmalloc(size);
151 #ifdef HAVE_MALLOC_SIZE
152 oldsize = zmalloc_size(ptr);
153 newptr = realloc(ptr,size);
154 if (!newptr) zmalloc_oom_handler(size);
155
156 update_zmalloc_stat_free(oldsize);
157 update_zmalloc_stat_alloc(zmalloc_size(newptr));
158 return newptr;
159 #else
160 realptr = (char*)ptr-PREFIX_SIZE;
161 oldsize = *((size_t*)realptr);
162 newptr = realloc(realptr,size+PREFIX_SIZE);
163 if (!newptr) zmalloc_oom_handler(size);
164
165 *((size_t*)newptr) = size;
166 update_zmalloc_stat_free(oldsize);
167 update_zmalloc_stat_alloc(size);
168 return (char*)newptr+PREFIX_SIZE;
169 #endif
170 }
171
172 /* Provide zmalloc_size() for systems where this function is not provided by
173 * malloc itself, given that in that case we store a header with this
174 * information as the first bytes of every allocation. */
175 #ifndef HAVE_MALLOC_SIZE
176 size_t zmalloc_size(void *ptr) {
177 void *realptr = (char*)ptr-PREFIX_SIZE;
178 size_t size = *((size_t*)realptr);
179 /* Assume at least that all the allocations are padded at sizeof(long) by
180 * the underlying allocator. */
181 if (size&(sizeof(long)-1)) size += sizeof(long)-(size&(sizeof(long)-1));
182 return size+PREFIX_SIZE;
183 }
184 #endif
185
186 void zfree(void *ptr) {
187 #ifndef HAVE_MALLOC_SIZE
188 void *realptr;
189 size_t oldsize;
190 #endif
191
192 if (ptr == NULL) return;
193 #ifdef HAVE_MALLOC_SIZE
194 update_zmalloc_stat_free(zmalloc_size(ptr));
195 free(ptr);
196 #else
197 realptr = (char*)ptr-PREFIX_SIZE;
198 oldsize = *((size_t*)realptr);
199 update_zmalloc_stat_free(oldsize+PREFIX_SIZE);
200 free(realptr);
201 #endif
202 }
203
204 char *zstrdup(const char *s) {
205 size_t l = strlen(s)+1;
206 char *p = zmalloc(l);
207
208 memcpy(p,s,l);
209 return p;
210 }
211
212 size_t zmalloc_used_memory(void) {
213 size_t um;
214 atomicGet(used_memory,um);
215 return um;
216 }
217
218 void zmalloc_set_oom_handler(void (*oom_handler)(size_t)) {
219 zmalloc_oom_handler = oom_handler;
220 }
221
222 /* Get the RSS information in an OS-specific way.
223 *
224 * WARNING: the function zmalloc_get_rss() is not designed to be fast
225 * and may not be called in the busy loops where Redis tries to release
226 * memory expiring or swapping out objects.
227 *
228 * For this kind of "fast RSS reporting" usages use instead the
229 * function RedisEstimateRSS() that is a much faster (and less precise)
230 * version of the function. */
231
232 #if defined(HAVE_PROC_STAT)
233 #include <unistd.h>
234 #include <sys/types.h>
235 #include <sys/stat.h>
236 #include <fcntl.h>
237
238 size_t zmalloc_get_rss(void) {
239 int page = sysconf(_SC_PAGESIZE);
240 size_t rss;
241 char buf[4096];
242 char filename[256];
243 int fd, count;
244 char *p, *x;
245
246 snprintf(filename,256,"/proc/%d/stat",getpid());
247 if ((fd = open(filename,O_RDONLY)) == -1) return 0;
248 if (read(fd,buf,4096) <= 0) {
249 close(fd);
250 return 0;
251 }
252 close(fd);
253
254 p = buf;
255 count = 23; /* RSS is the 24th field in /proc/<pid>/stat */
256 while(p && count--) {
257 p = strchr(p,' ');
258 if (p) p++;
259 }
260 if (!p) return 0;
261 x = strchr(p,' ');
262 if (!x) return 0;
263 *x = '\0';
264
265 rss = strtoll(p,NULL,10);
266 rss *= page;
267 return rss;
268 }
269 #elif defined(HAVE_TASKINFO)
270 #include <unistd.h>
271 #include <stdio.h>
272 #include <stdlib.h>
273 #include <sys/types.h>
274 #include <sys/sysctl.h>
275 #include <mach/task.h>
276 #include <mach/mach_init.h>
277
278 size_t zmalloc_get_rss(void) {
279 task_t task = MACH_PORT_NULL;
280 struct task_basic_info t_info;
281 mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
282
283 if (task_for_pid(current_task(), getpid(), &task) != KERN_SUCCESS)
284 return 0;
285 task_info(task, TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count);
286
287 return t_info.resident_size;
288 }
289 #else
290 size_t zmalloc_get_rss(void) {
291 /* If we can't get the RSS in an OS-specific way for this system just
292 * return the memory usage we estimated in zmalloc()..
293 *
294 * Fragmentation will appear to be always 1 (no fragmentation)
295 * of course... */
296 return zmalloc_used_memory();
297 }
298 #endif
299
300 /* Fragmentation = RSS / allocated-bytes */
301 float zmalloc_get_fragmentation_ratio(size_t rss) {
302 return (float)rss/zmalloc_used_memory();
303 }
304
305 /* Get the sum of the specified field (converted form kb to bytes) in
306 * /proc/self/smaps. The field must be specified with trailing ":" as it
307 * apperas in the smaps output.
308 *
309 * If a pid is specified, the information is extracted for such a pid,
310 * otherwise if pid is -1 the information is reported is about the
311 * current process.
312 *
313 * Example: zmalloc_get_smap_bytes_by_field("Rss:",-1);
314 */
315 #if defined(HAVE_PROC_SMAPS)
316 size_t zmalloc_get_smap_bytes_by_field(char *field, long pid) {
317 char line[1024];
318 size_t bytes = 0;
319 int flen = strlen(field);
320 FILE *fp;
321
322 if (pid == -1) {
323 fp = fopen("/proc/self/smaps","r");
324 } else {
325 char filename[128];
326 snprintf(filename,sizeof(filename),"/proc/%ld/smaps",pid);
327 fp = fopen(filename,"r");
328 }
329
330 if (!fp) return 0;
331 while(fgets(line,sizeof(line),fp) != NULL) {
332 if (strncmp(line,field,flen) == 0) {
333 char *p = strchr(line,'k');
334 if (p) {
335 *p = '\0';
336 bytes += strtol(line+flen,NULL,10) * 1024;
337 }
338 }
339 }
340 fclose(fp);
341 return bytes;
342 }
343 #else
344 size_t zmalloc_get_smap_bytes_by_field(char *field, long pid) {
345 ((void) field);
346 ((void) pid);
347 return 0;
348 }
349 #endif
350
351 size_t zmalloc_get_private_dirty(long pid) {
352 return zmalloc_get_smap_bytes_by_field("Private_Dirty:",pid);
353 }
354
355 /* Returns the size of physical memory (RAM) in bytes.
356 * It looks ugly, but this is the cleanest way to achive cross platform results.
357 * Cleaned up from:
358 *
359 * http://nadeausoftware.com/articles/2012/09/c_c_tip_how_get_physical_memory_size_system
360 *
361 * Note that this function:
362 * 1) Was released under the following CC attribution license:
363 * http://creativecommons.org/licenses/by/3.0/deed.en_US.
364 * 2) Was originally implemented by David Robert Nadeau.
365 * 3) Was modified for Redis by Matt Stancliff.
366 * 4) This note exists in order to comply with the original license.
367 */
368 size_t zmalloc_get_memory_size(void) {
369 #if defined(__unix__) || defined(__unix) || defined(unix) || \
370 (defined(__APPLE__) && defined(__MACH__))
371 #if defined(CTL_HW) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64))
372 int mib[2];
373 mib[0] = CTL_HW;
374 #if defined(HW_MEMSIZE)
375 mib[1] = HW_MEMSIZE; /* OSX. --------------------- */
376 #elif defined(HW_PHYSMEM64)
377 mib[1] = HW_PHYSMEM64; /* NetBSD, OpenBSD. --------- */
378 #endif
379 int64_t size = 0; /* 64-bit */
380 size_t len = sizeof(size);
381 if (sysctl( mib, 2, &size, &len, NULL, 0) == 0)
382 return (size_t)size;
383 return 0L; /* Failed? */
384
385 #elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
386 /* FreeBSD, Linux, OpenBSD, and Solaris. -------------------- */
387 return (size_t)sysconf(_SC_PHYS_PAGES) * (size_t)sysconf(_SC_PAGESIZE);
388
389 #elif defined(CTL_HW) && (defined(HW_PHYSMEM) || defined(HW_REALMEM))
390 /* DragonFly BSD, FreeBSD, NetBSD, OpenBSD, and OSX. -------- */
391 int mib[2];
392 mib[0] = CTL_HW;
393 #if defined(HW_REALMEM)
394 mib[1] = HW_REALMEM; /* FreeBSD. ----------------- */
395 #elif defined(HW_PYSMEM)
396 mib[1] = HW_PHYSMEM; /* Others. ------------------ */
397 #endif
398 unsigned int size = 0; /* 32-bit */
399 size_t len = sizeof(size);
400 if (sysctl(mib, 2, &size, &len, NULL, 0) == 0)
401 return (size_t)size;
402 return 0L; /* Failed? */
403 #else
404 return 0L; /* Unknown method to get the data. */
405 #endif
406 #else
407 return 0L; /* Unknown OS. */
408 #endif
409 }
410
411