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 | */ |
29 | uint64_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 | |
101 | uint64_t getMemoryAmount() |
102 | { |
103 | auto res = getMemoryAmountOrZero(); |
104 | if (!res) |
105 | throw std::runtime_error("Cannot determine memory amount" ); |
106 | return res; |
107 | } |
108 | |