1e2641e09Santirez /* zmalloc - total amount of allocated memory aware version of malloc()
2e2641e09Santirez *
3e2641e09Santirez * Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
4e2641e09Santirez * All rights reserved.
5e2641e09Santirez *
6e2641e09Santirez * Redistribution and use in source and binary forms, with or without
7e2641e09Santirez * modification, are permitted provided that the following conditions are met:
8e2641e09Santirez *
9e2641e09Santirez * * Redistributions of source code must retain the above copyright notice,
10e2641e09Santirez * this list of conditions and the following disclaimer.
11e2641e09Santirez * * Redistributions in binary form must reproduce the above copyright
12e2641e09Santirez * notice, this list of conditions and the following disclaimer in the
13e2641e09Santirez * documentation and/or other materials provided with the distribution.
14e2641e09Santirez * * Neither the name of Redis nor the names of its contributors may be used
15e2641e09Santirez * to endorse or promote products derived from this software without
16e2641e09Santirez * specific prior written permission.
17e2641e09Santirez *
18e2641e09Santirez * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19e2641e09Santirez * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20e2641e09Santirez * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21e2641e09Santirez * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22e2641e09Santirez * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23e2641e09Santirez * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24e2641e09Santirez * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25e2641e09Santirez * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26e2641e09Santirez * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27e2641e09Santirez * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28e2641e09Santirez * POSSIBILITY OF SUCH DAMAGE.
29e2641e09Santirez */
30e2641e09Santirez
31e2641e09Santirez #include <stdio.h>
32e2641e09Santirez #include <stdlib.h>
33d174eed5Santirez
34d174eed5Santirez /* This function provide us access to the original libc free(). This is useful
35d174eed5Santirez * for instance to free results obtained by backtrace_symbols(). We need
36d174eed5Santirez * to define this function before including zmalloc.h that may shadow the
37d174eed5Santirez * free implementation if we use jemalloc or another non standard allocator. */
zlibc_free(void * ptr)38d174eed5Santirez void zlibc_free(void *ptr) {
39d174eed5Santirez free(ptr);
40d174eed5Santirez }
41d174eed5Santirez
42e2641e09Santirez #include <string.h>
43e2641e09Santirez #include <pthread.h>
44e2641e09Santirez #include "config.h"
4567a1810bSantirez #include "zmalloc.h"
46e2641e09Santirez
477cdc98b6SPieter Noordhuis #ifdef HAVE_MALLOC_SIZE
487cdc98b6SPieter Noordhuis #define PREFIX_SIZE (0)
49e2641e09Santirez #else
505ae979bfSChris Lamb #if defined(__sun) || defined(__sparc) || defined(__sparc__)
517cdc98b6SPieter Noordhuis #define PREFIX_SIZE (sizeof(long long))
527cdc98b6SPieter Noordhuis #else
537cdc98b6SPieter Noordhuis #define PREFIX_SIZE (sizeof(size_t))
547cdc98b6SPieter Noordhuis #endif
557cdc98b6SPieter Noordhuis #endif
567cdc98b6SPieter Noordhuis
577cdc98b6SPieter Noordhuis /* Explicitly override malloc/free etc when using tcmalloc. */
587cdc98b6SPieter Noordhuis #if defined(USE_TCMALLOC)
597cdc98b6SPieter Noordhuis #define malloc(size) tc_malloc(size)
607cdc98b6SPieter Noordhuis #define calloc(count,size) tc_calloc(count,size)
617cdc98b6SPieter Noordhuis #define realloc(ptr,size) tc_realloc(ptr,size)
627cdc98b6SPieter Noordhuis #define free(ptr) tc_free(ptr)
6329d04257Santirez #elif defined(USE_JEMALLOC)
6429d04257Santirez #define malloc(size) je_malloc(size)
6529d04257Santirez #define calloc(count,size) je_calloc(count,size)
6629d04257Santirez #define realloc(ptr,size) je_realloc(ptr,size)
6729d04257Santirez #define free(ptr) je_free(ptr)
68e2641e09Santirez #endif
69e2641e09Santirez
70a953c883SMatt Stancliff #if defined(__ATOMIC_RELAXED)
71a953c883SMatt Stancliff #define update_zmalloc_stat_add(__n) __atomic_add_fetch(&used_memory, (__n), __ATOMIC_RELAXED)
72a953c883SMatt Stancliff #define update_zmalloc_stat_sub(__n) __atomic_sub_fetch(&used_memory, (__n), __ATOMIC_RELAXED)
73a953c883SMatt Stancliff #elif defined(HAVE_ATOMIC)
7480ff1fc6SPremysl Hruby #define update_zmalloc_stat_add(__n) __sync_add_and_fetch(&used_memory, (__n))
7580ff1fc6SPremysl Hruby #define update_zmalloc_stat_sub(__n) __sync_sub_and_fetch(&used_memory, (__n))
7680ff1fc6SPremysl Hruby #else
7780ff1fc6SPremysl Hruby #define update_zmalloc_stat_add(__n) do { \
7880ff1fc6SPremysl Hruby pthread_mutex_lock(&used_memory_mutex); \
7980ff1fc6SPremysl Hruby used_memory += (__n); \
8080ff1fc6SPremysl Hruby pthread_mutex_unlock(&used_memory_mutex); \
8180ff1fc6SPremysl Hruby } while(0)
8280ff1fc6SPremysl Hruby
8380ff1fc6SPremysl Hruby #define update_zmalloc_stat_sub(__n) do { \
8480ff1fc6SPremysl Hruby pthread_mutex_lock(&used_memory_mutex); \
8580ff1fc6SPremysl Hruby used_memory -= (__n); \
8680ff1fc6SPremysl Hruby pthread_mutex_unlock(&used_memory_mutex); \
8780ff1fc6SPremysl Hruby } while(0)
8880ff1fc6SPremysl Hruby
8980ff1fc6SPremysl Hruby #endif
9080ff1fc6SPremysl Hruby
91af0b2207Santirez #define update_zmalloc_stat_alloc(__n) do { \
92e2641e09Santirez size_t _n = (__n); \
93e2641e09Santirez if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
94e2641e09Santirez if (zmalloc_thread_safe) { \
9580ff1fc6SPremysl Hruby update_zmalloc_stat_add(_n); \
96e2641e09Santirez } else { \
97e2641e09Santirez used_memory += _n; \
98e2641e09Santirez } \
99e2641e09Santirez } while(0)
100e2641e09Santirez
10167a1810bSantirez #define update_zmalloc_stat_free(__n) do { \
102e2641e09Santirez size_t _n = (__n); \
103e2641e09Santirez if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
104e2641e09Santirez if (zmalloc_thread_safe) { \
10580ff1fc6SPremysl Hruby update_zmalloc_stat_sub(_n); \
106e2641e09Santirez } else { \
107e2641e09Santirez used_memory -= _n; \
108e2641e09Santirez } \
109e2641e09Santirez } while(0)
110e2641e09Santirez
111e2641e09Santirez static size_t used_memory = 0;
112e2641e09Santirez static int zmalloc_thread_safe = 0;
113e2641e09Santirez pthread_mutex_t used_memory_mutex = PTHREAD_MUTEX_INITIALIZER;
114e2641e09Santirez
zmalloc_default_oom(size_t size)1156fdc6354Santirez static void zmalloc_default_oom(size_t size) {
116e2641e09Santirez fprintf(stderr, "zmalloc: Out of memory trying to allocate %zu bytes\n",
117e2641e09Santirez size);
118e2641e09Santirez fflush(stderr);
119e2641e09Santirez abort();
120e2641e09Santirez }
121e2641e09Santirez
1226fdc6354Santirez static void (*zmalloc_oom_handler)(size_t) = zmalloc_default_oom;
1236fdc6354Santirez
zmalloc(size_t size)124e2641e09Santirez void *zmalloc(size_t size) {
125e2641e09Santirez void *ptr = malloc(size+PREFIX_SIZE);
126e2641e09Santirez
1276fdc6354Santirez if (!ptr) zmalloc_oom_handler(size);
128e2641e09Santirez #ifdef HAVE_MALLOC_SIZE
129af0b2207Santirez update_zmalloc_stat_alloc(zmalloc_size(ptr));
130e2641e09Santirez return ptr;
131e2641e09Santirez #else
132e2641e09Santirez *((size_t*)ptr) = size;
133af0b2207Santirez update_zmalloc_stat_alloc(size+PREFIX_SIZE);
134e2641e09Santirez return (char*)ptr+PREFIX_SIZE;
135e2641e09Santirez #endif
136e2641e09Santirez }
137e2641e09Santirez
zcalloc(size_t size)138399f2f40SBenjamin Kramer void *zcalloc(size_t size) {
139399f2f40SBenjamin Kramer void *ptr = calloc(1, size+PREFIX_SIZE);
140399f2f40SBenjamin Kramer
1416fdc6354Santirez if (!ptr) zmalloc_oom_handler(size);
142399f2f40SBenjamin Kramer #ifdef HAVE_MALLOC_SIZE
143af0b2207Santirez update_zmalloc_stat_alloc(zmalloc_size(ptr));
144399f2f40SBenjamin Kramer return ptr;
145399f2f40SBenjamin Kramer #else
146399f2f40SBenjamin Kramer *((size_t*)ptr) = size;
147af0b2207Santirez update_zmalloc_stat_alloc(size+PREFIX_SIZE);
148399f2f40SBenjamin Kramer return (char*)ptr+PREFIX_SIZE;
149399f2f40SBenjamin Kramer #endif
150399f2f40SBenjamin Kramer }
151399f2f40SBenjamin Kramer
zrealloc(void * ptr,size_t size)152e2641e09Santirez void *zrealloc(void *ptr, size_t size) {
153e2641e09Santirez #ifndef HAVE_MALLOC_SIZE
154e2641e09Santirez void *realptr;
155e2641e09Santirez #endif
156e2641e09Santirez size_t oldsize;
157e2641e09Santirez void *newptr;
158e2641e09Santirez
159e2641e09Santirez if (ptr == NULL) return zmalloc(size);
160e2641e09Santirez #ifdef HAVE_MALLOC_SIZE
16129d04257Santirez oldsize = zmalloc_size(ptr);
162e2641e09Santirez newptr = realloc(ptr,size);
1636fdc6354Santirez if (!newptr) zmalloc_oom_handler(size);
164e2641e09Santirez
16567a1810bSantirez update_zmalloc_stat_free(oldsize);
166af0b2207Santirez update_zmalloc_stat_alloc(zmalloc_size(newptr));
167e2641e09Santirez return newptr;
168e2641e09Santirez #else
169e2641e09Santirez realptr = (char*)ptr-PREFIX_SIZE;
170e2641e09Santirez oldsize = *((size_t*)realptr);
171e2641e09Santirez newptr = realloc(realptr,size+PREFIX_SIZE);
1721caa627eSantirez if (!newptr) zmalloc_oom_handler(size);
173e2641e09Santirez
174e2641e09Santirez *((size_t*)newptr) = size;
17567a1810bSantirez update_zmalloc_stat_free(oldsize);
176af0b2207Santirez update_zmalloc_stat_alloc(size);
177e2641e09Santirez return (char*)newptr+PREFIX_SIZE;
178e2641e09Santirez #endif
179e2641e09Santirez }
180e2641e09Santirez
181442246ddSantirez /* Provide zmalloc_size() for systems where this function is not provided by
18211e81a1eSantirez * malloc itself, given that in that case we store a header with this
183442246ddSantirez * information as the first bytes of every allocation. */
184442246ddSantirez #ifndef HAVE_MALLOC_SIZE
zmalloc_size(void * ptr)185442246ddSantirez size_t zmalloc_size(void *ptr) {
186442246ddSantirez void *realptr = (char*)ptr-PREFIX_SIZE;
187442246ddSantirez size_t size = *((size_t*)realptr);
188442246ddSantirez /* Assume at least that all the allocations are padded at sizeof(long) by
189442246ddSantirez * the underlying allocator. */
190442246ddSantirez if (size&(sizeof(long)-1)) size += sizeof(long)-(size&(sizeof(long)-1));
191442246ddSantirez return size+PREFIX_SIZE;
192442246ddSantirez }
193442246ddSantirez #endif
194442246ddSantirez
zfree(void * ptr)195e2641e09Santirez void zfree(void *ptr) {
196e2641e09Santirez #ifndef HAVE_MALLOC_SIZE
197e2641e09Santirez void *realptr;
198e2641e09Santirez size_t oldsize;
199e2641e09Santirez #endif
200e2641e09Santirez
201e2641e09Santirez if (ptr == NULL) return;
202e2641e09Santirez #ifdef HAVE_MALLOC_SIZE
20329d04257Santirez update_zmalloc_stat_free(zmalloc_size(ptr));
204e2641e09Santirez free(ptr);
205e2641e09Santirez #else
206e2641e09Santirez realptr = (char*)ptr-PREFIX_SIZE;
207e2641e09Santirez oldsize = *((size_t*)realptr);
20867a1810bSantirez update_zmalloc_stat_free(oldsize+PREFIX_SIZE);
209e2641e09Santirez free(realptr);
210e2641e09Santirez #endif
211e2641e09Santirez }
212e2641e09Santirez
zstrdup(const char * s)213e2641e09Santirez char *zstrdup(const char *s) {
214e2641e09Santirez size_t l = strlen(s)+1;
215e2641e09Santirez char *p = zmalloc(l);
216e2641e09Santirez
217e2641e09Santirez memcpy(p,s,l);
218e2641e09Santirez return p;
219e2641e09Santirez }
220e2641e09Santirez
zmalloc_used_memory(void)221e2641e09Santirez size_t zmalloc_used_memory(void) {
222e2641e09Santirez size_t um;
223e2641e09Santirez
22480ff1fc6SPremysl Hruby if (zmalloc_thread_safe) {
225a953c883SMatt Stancliff #if defined(__ATOMIC_RELAXED) || defined(HAVE_ATOMIC)
226f9bca13aSMatt Stancliff um = update_zmalloc_stat_add(0);
22780ff1fc6SPremysl Hruby #else
22880ff1fc6SPremysl Hruby pthread_mutex_lock(&used_memory_mutex);
229e2641e09Santirez um = used_memory;
23080ff1fc6SPremysl Hruby pthread_mutex_unlock(&used_memory_mutex);
23180ff1fc6SPremysl Hruby #endif
23280ff1fc6SPremysl Hruby }
23380ff1fc6SPremysl Hruby else {
23480ff1fc6SPremysl Hruby um = used_memory;
23580ff1fc6SPremysl Hruby }
23680ff1fc6SPremysl Hruby
237e2641e09Santirez return um;
238e2641e09Santirez }
239e2641e09Santirez
zmalloc_enable_thread_safeness(void)240e2641e09Santirez void zmalloc_enable_thread_safeness(void) {
241e2641e09Santirez zmalloc_thread_safe = 1;
242e2641e09Santirez }
243eddb388eSantirez
zmalloc_set_oom_handler(void (* oom_handler)(size_t))2446fdc6354Santirez void zmalloc_set_oom_handler(void (*oom_handler)(size_t)) {
2456fdc6354Santirez zmalloc_oom_handler = oom_handler;
2466fdc6354Santirez }
2476fdc6354Santirez
24892e28228Santirez /* Get the RSS information in an OS-specific way.
24992e28228Santirez *
25092e28228Santirez * WARNING: the function zmalloc_get_rss() is not designed to be fast
25192e28228Santirez * and may not be called in the busy loops where Redis tries to release
25292e28228Santirez * memory expiring or swapping out objects.
25392e28228Santirez *
25492e28228Santirez * For this kind of "fast RSS reporting" usages use instead the
25592e28228Santirez * function RedisEstimateRSS() that is a much faster (and less precise)
2569d09ce39Sguiquanz * version of the function. */
25773db2accSantirez
2583cb43283Santirez #if defined(HAVE_PROC_STAT)
25973db2accSantirez #include <unistd.h>
26073db2accSantirez #include <sys/types.h>
26173db2accSantirez #include <sys/stat.h>
26273db2accSantirez #include <fcntl.h>
26373db2accSantirez
zmalloc_get_rss(void)26492e28228Santirez size_t zmalloc_get_rss(void) {
265eddb388eSantirez int page = sysconf(_SC_PAGESIZE);
266eddb388eSantirez size_t rss;
267eddb388eSantirez char buf[4096];
268eddb388eSantirez char filename[256];
269eddb388eSantirez int fd, count;
270eddb388eSantirez char *p, *x;
271eddb388eSantirez
272eddb388eSantirez snprintf(filename,256,"/proc/%d/stat",getpid());
273eddb388eSantirez if ((fd = open(filename,O_RDONLY)) == -1) return 0;
274eddb388eSantirez if (read(fd,buf,4096) <= 0) {
275eddb388eSantirez close(fd);
276eddb388eSantirez return 0;
277eddb388eSantirez }
278eddb388eSantirez close(fd);
279eddb388eSantirez
280eddb388eSantirez p = buf;
281eddb388eSantirez count = 23; /* RSS is the 24th field in /proc/<pid>/stat */
282eddb388eSantirez while(p && count--) {
283eddb388eSantirez p = strchr(p,' ');
284eddb388eSantirez if (p) p++;
285eddb388eSantirez }
286eddb388eSantirez if (!p) return 0;
287eddb388eSantirez x = strchr(p,' ');
288eddb388eSantirez if (!x) return 0;
289eddb388eSantirez *x = '\0';
290eddb388eSantirez
291eddb388eSantirez rss = strtoll(p,NULL,10);
292eddb388eSantirez rss *= page;
29392e28228Santirez return rss;
294eddb388eSantirez }
29573db2accSantirez #elif defined(HAVE_TASKINFO)
29673db2accSantirez #include <unistd.h>
29773db2accSantirez #include <stdio.h>
29873db2accSantirez #include <stdlib.h>
29973db2accSantirez #include <sys/types.h>
30073db2accSantirez #include <sys/sysctl.h>
30173db2accSantirez #include <mach/task.h>
30273db2accSantirez #include <mach/mach_init.h>
30373db2accSantirez
zmalloc_get_rss(void)30492e28228Santirez size_t zmalloc_get_rss(void) {
30573db2accSantirez task_t task = MACH_PORT_NULL;
30673db2accSantirez struct task_basic_info t_info;
30773db2accSantirez mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
30873db2accSantirez
30973db2accSantirez if (task_for_pid(current_task(), getpid(), &task) != KERN_SUCCESS)
31073db2accSantirez return 0;
31173db2accSantirez task_info(task, TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count);
31273db2accSantirez
31392e28228Santirez return t_info.resident_size;
31473db2accSantirez }
31573db2accSantirez #else
zmalloc_get_rss(void)316c4df22afSantirez size_t zmalloc_get_rss(void) {
31792e28228Santirez /* If we can't get the RSS in an OS-specific way for this system just
31892e28228Santirez * return the memory usage we estimated in zmalloc()..
31992e28228Santirez *
32092e28228Santirez * Fragmentation will appear to be always 1 (no fragmentation)
32192e28228Santirez * of course... */
32292e28228Santirez return zmalloc_used_memory();
32373db2accSantirez }
32473db2accSantirez #endif
32592e28228Santirez
32692e28228Santirez /* Fragmentation = RSS / allocated-bytes */
zmalloc_get_fragmentation_ratio(size_t rss)32793253c27Santirez float zmalloc_get_fragmentation_ratio(size_t rss) {
32893253c27Santirez return (float)rss/zmalloc_used_memory();
32992e28228Santirez }
3303bfeb9c1Santirez
3313ef0876bSantirez /* Get the sum of the specified field (converted form kb to bytes) in
3323ef0876bSantirez * /proc/self/smaps. The field must be specified with trailing ":" as it
3333ef0876bSantirez * apperas in the smaps output.
3343ef0876bSantirez *
3353ef0876bSantirez * Example: zmalloc_get_smap_bytes_by_field("Rss:");
3363ef0876bSantirez */
3373cb43283Santirez #if defined(HAVE_PROC_SMAPS)
zmalloc_get_smap_bytes_by_field(char * field)3383ef0876bSantirez size_t zmalloc_get_smap_bytes_by_field(char *field) {
3393bfeb9c1Santirez char line[1024];
3403ef0876bSantirez size_t bytes = 0;
3413bfeb9c1Santirez FILE *fp = fopen("/proc/self/smaps","r");
3423ef0876bSantirez int flen = strlen(field);
3433bfeb9c1Santirez
3443bfeb9c1Santirez if (!fp) return 0;
3453bfeb9c1Santirez while(fgets(line,sizeof(line),fp) != NULL) {
3463ef0876bSantirez if (strncmp(line,field,flen) == 0) {
3473bfeb9c1Santirez char *p = strchr(line,'k');
3483bfeb9c1Santirez if (p) {
3493bfeb9c1Santirez *p = '\0';
3503ef0876bSantirez bytes += strtol(line+flen,NULL,10) * 1024;
3513bfeb9c1Santirez }
3523bfeb9c1Santirez }
3533bfeb9c1Santirez }
3543bfeb9c1Santirez fclose(fp);
3553ef0876bSantirez return bytes;
3563bfeb9c1Santirez }
3573bfeb9c1Santirez #else
zmalloc_get_smap_bytes_by_field(char * field)3583ef0876bSantirez size_t zmalloc_get_smap_bytes_by_field(char *field) {
35962090669Santirez ((void) field);
3603bfeb9c1Santirez return 0;
3613bfeb9c1Santirez }
3623bfeb9c1Santirez #endif
3633ef0876bSantirez
zmalloc_get_private_dirty(void)3643ef0876bSantirez size_t zmalloc_get_private_dirty(void) {
3653ef0876bSantirez return zmalloc_get_smap_bytes_by_field("Private_Dirty:");
3663ef0876bSantirez }
367615f6923Santirez
368615f6923Santirez /* Returns the size of physical memory (RAM) in bytes.
369615f6923Santirez * It looks ugly, but this is the cleanest way to achive cross platform results.
370615f6923Santirez * Cleaned up from:
371*9a635431Santirez *
372615f6923Santirez * http://nadeausoftware.com/articles/2012/09/c_c_tip_how_get_physical_memory_size_system
373*9a635431Santirez *
374*9a635431Santirez * Note that this function:
375*9a635431Santirez * 1) Was released under the following CC attribution license:
376*9a635431Santirez * http://creativecommons.org/licenses/by/3.0/deed.en_US.
377*9a635431Santirez * 2) Was originally implemented by David Robert Nadeau.
378*9a635431Santirez * 3) Was modified for Redis by Matt Stancliff.
379*9a635431Santirez * 4) This note exists in order to comply with the original license.
380615f6923Santirez */
zmalloc_get_memory_size(void)381615f6923Santirez size_t zmalloc_get_memory_size(void) {
382615f6923Santirez #if defined(__unix__) || defined(__unix) || defined(unix) || \
383615f6923Santirez (defined(__APPLE__) && defined(__MACH__))
384615f6923Santirez #if defined(CTL_HW) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64))
385615f6923Santirez int mib[2];
386615f6923Santirez mib[0] = CTL_HW;
387615f6923Santirez #if defined(HW_MEMSIZE)
388615f6923Santirez mib[1] = HW_MEMSIZE; /* OSX. --------------------- */
389615f6923Santirez #elif defined(HW_PHYSMEM64)
390615f6923Santirez mib[1] = HW_PHYSMEM64; /* NetBSD, OpenBSD. --------- */
391615f6923Santirez #endif
392615f6923Santirez int64_t size = 0; /* 64-bit */
393615f6923Santirez size_t len = sizeof(size);
394615f6923Santirez if (sysctl( mib, 2, &size, &len, NULL, 0) == 0)
395615f6923Santirez return (size_t)size;
396615f6923Santirez return 0L; /* Failed? */
397615f6923Santirez
398615f6923Santirez #elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
399615f6923Santirez /* FreeBSD, Linux, OpenBSD, and Solaris. -------------------- */
400615f6923Santirez return (size_t)sysconf(_SC_PHYS_PAGES) * (size_t)sysconf(_SC_PAGESIZE);
401615f6923Santirez
402615f6923Santirez #elif defined(CTL_HW) && (defined(HW_PHYSMEM) || defined(HW_REALMEM))
403615f6923Santirez /* DragonFly BSD, FreeBSD, NetBSD, OpenBSD, and OSX. -------- */
404615f6923Santirez int mib[2];
405615f6923Santirez mib[0] = CTL_HW;
406615f6923Santirez #if defined(HW_REALMEM)
407615f6923Santirez mib[1] = HW_REALMEM; /* FreeBSD. ----------------- */
408615f6923Santirez #elif defined(HW_PYSMEM)
409615f6923Santirez mib[1] = HW_PHYSMEM; /* Others. ------------------ */
410615f6923Santirez #endif
411615f6923Santirez unsigned int size = 0; /* 32-bit */
412615f6923Santirez size_t len = sizeof(size);
413615f6923Santirez if (sysctl(mib, 2, &size, &len, NULL, 0) == 0)
414615f6923Santirez return (size_t)size;
415615f6923Santirez return 0L; /* Failed? */
416615f6923Santirez #endif /* sysctl and sysconf variants */
417615f6923Santirez
418615f6923Santirez #else
419615f6923Santirez return 0L; /* Unknown OS. */
420615f6923Santirez #endif
421615f6923Santirez }
422615f6923Santirez
423615f6923Santirez
424