1 #if !defined(spp_memory_h_guard)
2 #define spp_memory_h_guard
3 
4 #include <cstdint>
5 #include <cstring>
6 #include <cstdlib>
7 
8 #if defined(_WIN32) || defined( __CYGWIN__)
9     #define SPP_WIN
10 #endif
11 
12 #ifdef SPP_WIN
13     #include <windows.h>
14     #include <Psapi.h>
15     #undef min
16     #undef max
17 #elif defined(__linux__)
18     #include <sys/types.h>
19     #include <sys/sysinfo.h>
20 #elif defined(__FreeBSD__)
21     #include <paths.h>
22     #include <fcntl.h>
23     #include <kvm.h>
24     #include <unistd.h>
25     #include <sys/sysctl.h>
26     #include <sys/user.h>
27 #endif
28 
29 namespace spp
30 {
GetSystemMemory()31     uint64_t GetSystemMemory()
32     {
33 #ifdef SPP_WIN
34         MEMORYSTATUSEX memInfo;
35         memInfo.dwLength = sizeof(MEMORYSTATUSEX);
36         GlobalMemoryStatusEx(&memInfo);
37         return static_cast<uint64_t>(memInfo.ullTotalPageFile);
38 #elif defined(__linux__)
39         struct sysinfo memInfo;
40         sysinfo (&memInfo);
41         auto totalVirtualMem = memInfo.totalram;
42 
43         totalVirtualMem += memInfo.totalswap;
44         totalVirtualMem *= memInfo.mem_unit;
45         return static_cast<uint64_t>(totalVirtualMem);
46 #elif defined(__FreeBSD__)
47         kvm_t *kd;
48         u_int pageCnt;
49         size_t pageCntLen = sizeof(pageCnt);
50         u_int pageSize;
51         struct kvm_swap kswap;
52         uint64_t totalVirtualMem;
53 
54         pageSize = static_cast<u_int>(getpagesize());
55 
56         sysctlbyname("vm.stats.vm.v_page_count", &pageCnt, &pageCntLen, NULL, 0);
57         totalVirtualMem = pageCnt * pageSize;
58 
59         kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open");
60         kvm_getswapinfo(kd, &kswap, 1, 0);
61         kvm_close(kd);
62         totalVirtualMem += kswap.ksw_total * pageSize;
63 
64         return totalVirtualMem;
65 #else
66         return 0;
67 #endif
68     }
69 
GetTotalMemoryUsed()70     uint64_t GetTotalMemoryUsed()
71     {
72 #ifdef SPP_WIN
73         MEMORYSTATUSEX memInfo;
74         memInfo.dwLength = sizeof(MEMORYSTATUSEX);
75         GlobalMemoryStatusEx(&memInfo);
76         return static_cast<uint64_t>(memInfo.ullTotalPageFile - memInfo.ullAvailPageFile);
77 #elif defined(__linux__)
78         struct sysinfo memInfo;
79         sysinfo(&memInfo);
80         auto virtualMemUsed = memInfo.totalram - memInfo.freeram;
81 
82         virtualMemUsed += memInfo.totalswap - memInfo.freeswap;
83         virtualMemUsed *= memInfo.mem_unit;
84 
85         return static_cast<uint64_t>(virtualMemUsed);
86 #elif defined(__FreeBSD__)
87         kvm_t *kd;
88         u_int pageSize;
89         u_int pageCnt, freeCnt;
90         size_t pageCntLen = sizeof(pageCnt);
91         size_t freeCntLen = sizeof(freeCnt);
92         struct kvm_swap kswap;
93         uint64_t virtualMemUsed;
94 
95         pageSize = static_cast<u_int>(getpagesize());
96 
97         sysctlbyname("vm.stats.vm.v_page_count", &pageCnt, &pageCntLen, NULL, 0);
98         sysctlbyname("vm.stats.vm.v_free_count", &freeCnt, &freeCntLen, NULL, 0);
99         virtualMemUsed = (pageCnt - freeCnt) * pageSize;
100 
101         kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open");
102         kvm_getswapinfo(kd, &kswap, 1, 0);
103         kvm_close(kd);
104         virtualMemUsed += kswap.ksw_used * pageSize;
105 
106         return virtualMemUsed;
107 #else
108         return 0;
109 #endif
110     }
111 
GetProcessMemoryUsed()112     uint64_t GetProcessMemoryUsed()
113     {
114 #ifdef SPP_WIN
115         PROCESS_MEMORY_COUNTERS_EX pmc;
116         GetProcessMemoryInfo(GetCurrentProcess(), reinterpret_cast<PPROCESS_MEMORY_COUNTERS>(&pmc), sizeof(pmc));
117         return static_cast<uint64_t>(pmc.PrivateUsage);
118 #elif defined(__linux__)
119         auto parseLine =
120             [](char* line)->int
121             {
122                 auto i = strlen(line);
123 
124                 while(*line < '0' || *line > '9')
125                 {
126                     line++;
127                 }
128 
129                 line[i-3] = '\0';
130                 i = atoi(line);
131                 return i;
132             };
133 
134         auto file = fopen("/proc/self/status", "r");
135         auto result = -1;
136         char line[128];
137 
138         while(fgets(line, 128, file) != nullptr)
139         {
140             if(strncmp(line, "VmSize:", 7) == 0)
141             {
142                 result = parseLine(line);
143                 break;
144             }
145         }
146 
147         fclose(file);
148         return static_cast<uint64_t>(result) * 1024;
149 #elif defined(__FreeBSD__)
150         struct kinfo_proc info;
151         size_t infoLen = sizeof(info);
152         int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() };
153 
154         sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &infoLen, NULL, 0);
155 #ifdef __DragonFly__
156         return static_cast<uint64_t>(info.kp_vm_rssize * getpagesize());
157 #else
158         return static_cast<uint64_t>(info.ki_rssize * getpagesize());
159 #endif
160 #else
161         return 0;
162 #endif
163     }
164 
GetPhysicalMemory()165     uint64_t GetPhysicalMemory()
166     {
167 #ifdef SPP_WIN
168         MEMORYSTATUSEX memInfo;
169         memInfo.dwLength = sizeof(MEMORYSTATUSEX);
170         GlobalMemoryStatusEx(&memInfo);
171         return static_cast<uint64_t>(memInfo.ullTotalPhys);
172 #elif defined(__linux__)
173         struct sysinfo memInfo;
174         sysinfo(&memInfo);
175 
176         auto totalPhysMem = memInfo.totalram;
177 
178         totalPhysMem *= memInfo.mem_unit;
179         return static_cast<uint64_t>(totalPhysMem);
180 #elif defined(__FreeBSD__)
181         u_long physMem;
182         size_t physMemLen = sizeof(physMem);
183         int mib[] = { CTL_HW, HW_PHYSMEM };
184 
185         sysctl(mib, sizeof(mib) / sizeof(*mib), &physMem, &physMemLen, NULL, 0);
186         return physMem;
187 #else
188         return 0;
189 #endif
190     }
191 
192 }
193 
194 #endif // spp_memory_h_guard
195