1#include <stdexcept>
2#include "common/getMemoryAmount.h"
3
4// http://nadeausoftware.com/articles/2012/09/c_c_tip_how_get_physical_memory_size_system
5
6/*
7 * Author: David Robert Nadeau
8 * Site: http://NadeauSoftware.com/
9 * License: Creative Commons Attribution 3.0 Unported License
10 * http://creativecommons.org/licenses/by/3.0/deed.en_US
11 */
12
13#if defined(WIN32) || defined(_WIN32)
14#include <Windows.h>
15#else
16#include <unistd.h>
17#include <sys/types.h>
18#include <sys/param.h>
19#if defined(BSD)
20#include <sys/sysctl.h>
21#endif
22#endif
23
24
25/**
26 * Returns the size of physical memory (RAM) in bytes.
27 * Returns 0 on unsupported platform
28 */
29uint64_t getMemoryAmountOrZero()
30{
31#if defined(_WIN32) && (defined(__CYGWIN__) || defined(__CYGWIN32__))
32 /* Cygwin under Windows. ------------------------------------ */
33 /* New 64-bit MEMORYSTATUSEX isn't available. Use old 32.bit */
34 MEMORYSTATUS status;
35 status.dwLength = sizeof(status);
36 GlobalMemoryStatus( &status );
37 return status.dwTotalPhys;
38
39#elif defined(WIN32) || defined(_WIN32)
40 /* Windows. ------------------------------------------------- */
41 /* Use new 64-bit MEMORYSTATUSEX, not old 32-bit MEMORYSTATUS */
42 MEMORYSTATUSEX status;
43 status.dwLength = sizeof(status);
44 GlobalMemoryStatusEx( &status );
45 return status.ullTotalPhys;
46
47#else
48 /* UNIX variants. ------------------------------------------- */
49 /* Prefer sysctl() over sysconf() except sysctl() HW_REALMEM and HW_PHYSMEM */
50
51#if defined(CTL_HW) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64))
52 int mib[2];
53 mib[0] = CTL_HW;
54#if defined(HW_MEMSIZE)
55 mib[1] = HW_MEMSIZE; /* OSX. --------------------- */
56#elif defined(HW_PHYSMEM64)
57 mib[1] = HW_PHYSMEM64; /* NetBSD, OpenBSD. --------- */
58#endif
59 uint64_t size = 0; /* 64-bit */
60 size_t len = sizeof(size);
61 if ( sysctl( mib, 2, &size, &len, NULL, 0 ) == 0 ) {
62 return size;
63 }
64 return 0; /* Failed? */
65
66#elif defined(_SC_AIX_REALMEM)
67 /* AIX. ----------------------------------------------------- */
68 return sysconf( _SC_AIX_REALMEM ) * 1024;
69
70#elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
71 /* FreeBSD, Linux, OpenBSD, and Solaris. -------------------- */
72 return (uint64_t)sysconf( _SC_PHYS_PAGES )
73 * (uint64_t)sysconf( _SC_PAGESIZE );
74
75#elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGE_SIZE)
76 /* Legacy. -------------------------------------------------- */
77 return (uint64_t)sysconf( _SC_PHYS_PAGES )
78 * (uint64_t)sysconf( _SC_PAGE_SIZE );
79
80#elif defined(CTL_HW) && (defined(HW_PHYSMEM) || defined(HW_REALMEM))
81 /* DragonFly BSD, FreeBSD, NetBSD, OpenBSD, and OSX. -------- */
82 int mib[2];
83 mib[0] = CTL_HW;
84#if defined(HW_REALMEM)
85 mib[1] = HW_REALMEM; /* FreeBSD. ----------------- */
86#elif defined(HW_PYSMEM)
87 mib[1] = HW_PHYSMEM; /* Others. ------------------ */
88#endif
89 unsigned int size = 0; /* 32-bit */
90 size_t len = sizeof( size );
91 if ( sysctl( mib, 2, &size, &len, NULL, 0 ) == 0 ) {
92 return size;
93 }
94 return 0; /* Failed? */
95#endif /* sysctl and sysconf variants */
96
97#endif
98}
99
100
101uint64_t getMemoryAmount()
102{
103 auto res = getMemoryAmountOrZero();
104 if (!res)
105 throw std::runtime_error("Cannot determine memory amount");
106 return res;
107}
108