Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
MemoryUsage.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#include "MemoryUsage.h"
7
8#include <cstring>
9#include <iomanip>
10#include <sstream>
11#include <vector>
12
13#if PLATFORM == PLATFORM_WINDOWS
14#include <windows.h>
15#include <psapi.h>
16#include <sysinfoapi.h>
17#elif PLATFORM == PLATFORM_UNIX || PLATFORM == PLATFORM_APPLE
18#include <sys/resource.h>
19#include <unistd.h>
20
21#if PLATFORM == PLATFORM_UNIX
22#include <fstream>
23#include <sys/sysinfo.h>
24#endif
25
26#if PLATFORM == PLATFORM_APPLE
27#include <mach/mach.h>
28#include <sys/sysctl.h>
29#endif
30#endif
31
32namespace
33{
34 void AppendMemoryField(std::vector<std::string>& fields, char const* label, uint64 bytes)
35 {
36 std::ostringstream stream;
37 stream << label << ' ' << Skyfire::FormatMemorySize(bytes);
38 fields.push_back(stream.str());
39 }
40
41 void AppendPercentageField(std::vector<std::string>& fields, char const* label, double percent)
42 {
43 std::ostringstream stream;
44 stream << label << ' ' << std::fixed << std::setprecision(1) << percent << '%';
45 fields.push_back(stream.str());
46 }
47}
48
50{
52
53#if PLATFORM == PLATFORM_WINDOWS
54 PROCESS_MEMORY_COUNTERS_EX counters;
55 memset(&counters, 0, sizeof(counters));
56 counters.cb = sizeof(counters);
57
58 if (!GetProcessMemoryInfo(GetCurrentProcess(), reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&counters), sizeof(counters)))
59 return false;
60
61 usage.residentBytes = static_cast<uint64>(counters.WorkingSetSize);
62 usage.peakResidentBytes = static_cast<uint64>(counters.PeakWorkingSetSize);
63 usage.privateBytes = static_cast<uint64>(counters.PrivateUsage);
64 usage.hasResidentBytes = true;
65 usage.hasPeakResidentBytes = true;
66 usage.hasPrivateBytes = true;
67 return true;
68#elif PLATFORM == PLATFORM_UNIX || PLATFORM == PLATFORM_APPLE
69 bool hasAnyValue = false;
70
71#if PLATFORM == PLATFORM_UNIX
72 std::ifstream statm("/proc/self/statm");
73 uint64 virtualPages = 0;
74 uint64 residentPages = 0;
75
76 if (statm >> virtualPages >> residentPages)
77 {
78 long pageSize = sysconf(_SC_PAGESIZE);
79 if (pageSize > 0)
80 {
81 usage.virtualBytes = virtualPages * static_cast<uint64>(pageSize);
82 usage.residentBytes = residentPages * static_cast<uint64>(pageSize);
83 usage.hasVirtualBytes = true;
84 usage.hasResidentBytes = true;
85 hasAnyValue = true;
86 }
87 }
88#endif
89
90 struct rusage resourceUsage;
91 if (getrusage(RUSAGE_SELF, &resourceUsage) == 0)
92 {
93#if PLATFORM == PLATFORM_APPLE
94 usage.peakResidentBytes = static_cast<uint64>(resourceUsage.ru_maxrss);
95#else
96 usage.peakResidentBytes = static_cast<uint64>(resourceUsage.ru_maxrss) * 1024;
97#endif
98 usage.hasPeakResidentBytes = true;
99 hasAnyValue = true;
100 }
101
102 return hasAnyValue;
103#else
104 return false;
105#endif
106}
107
109{
111
112#if PLATFORM == PLATFORM_WINDOWS
113 MEMORYSTATUSEX memoryStatus;
114 memoryStatus.dwLength = sizeof(memoryStatus);
115
116 if (!GlobalMemoryStatusEx(&memoryStatus))
117 return false;
118
119 usage.totalPhysicalBytes = memoryStatus.ullTotalPhys;
120 usage.availablePhysicalBytes = memoryStatus.ullAvailPhys;
121 usage.usedPhysicalBytes = memoryStatus.ullTotalPhys - memoryStatus.ullAvailPhys;
122 usage.totalVirtualBytes = memoryStatus.ullTotalPageFile;
123 usage.usedVirtualBytes = memoryStatus.ullTotalPageFile - memoryStatus.ullAvailPageFile;
124 usage.totalSwapBytes = 0;
125 usage.usedSwapBytes = 0;
126
127 if (usage.totalPhysicalBytes > 0)
128 {
129 usage.physicalUsagePercent = (static_cast<double>(usage.usedPhysicalBytes) /
130 static_cast<double>(usage.totalPhysicalBytes)) * 100.0;
131 }
132
133 if (usage.totalVirtualBytes > 0)
134 {
135 usage.virtualUsagePercent = (static_cast<double>(usage.usedVirtualBytes) /
136 static_cast<double>(usage.totalVirtualBytes)) * 100.0;
137 }
138
139 usage.hasValidData = true;
140 return true;
141
142#elif PLATFORM == PLATFORM_UNIX
143 std::ifstream meminfo("/proc/meminfo");
144 if (!meminfo.is_open())
145 return false;
146
147 std::string key;
148 uint64 value;
149 std::string unit;
150 uint64 memTotal = 0, memAvailable = 0, swapTotal = 0, swapFree = 0;
151
152 while (meminfo >> key >> value >> unit)
153 {
154 if (key == "MemTotal:")
155 memTotal = value * 1024;
156 else if (key == "MemAvailable:")
157 memAvailable = value * 1024;
158 else if (key == "SwapTotal:")
159 swapTotal = value * 1024;
160 else if (key == "SwapFree:")
161 swapFree = value * 1024;
162 }
163
164 if (memTotal == 0)
165 return false;
166
167 usage.totalPhysicalBytes = memTotal;
168 usage.availablePhysicalBytes = memAvailable > 0 ? memAvailable : 0;
169 usage.usedPhysicalBytes = memTotal - (memAvailable > 0 ? memAvailable : 0);
170 usage.totalSwapBytes = swapTotal;
171 usage.usedSwapBytes = swapTotal - swapFree;
172 usage.totalVirtualBytes = memTotal + swapTotal;
173 usage.usedVirtualBytes = usage.usedPhysicalBytes + usage.usedSwapBytes;
174
175 if (usage.totalPhysicalBytes > 0)
176 {
177 usage.physicalUsagePercent = (static_cast<double>(usage.usedPhysicalBytes) /
178 static_cast<double>(usage.totalPhysicalBytes)) * 100.0;
179 }
180
181 if (usage.totalVirtualBytes > 0)
182 {
183 usage.virtualUsagePercent = (static_cast<double>(usage.usedVirtualBytes) /
184 static_cast<double>(usage.totalVirtualBytes)) * 100.0;
185 }
186
187 usage.hasValidData = true;
188 return true;
189
190#elif PLATFORM == PLATFORM_APPLE
191 int mib[2];
192 size_t length;
193
194 mib[0] = CTL_HW;
195 mib[1] = HW_MEMSIZE;
196 length = sizeof(uint64_t);
197 if (sysctl(mib, 2, &usage.totalPhysicalBytes, &length, nullptr, 0) != 0)
198 return false;
199
200 vm_statistics64_data_t vmStats;
201 mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
202 kern_return_t kernReturn = host_statistics64(mach_host_self(),
203 HOST_VM_INFO64,
204 reinterpret_cast<host_info_t>(&vmStats),
205 &count);
206
207 if (kernReturn != KERN_SUCCESS)
208 return false;
209
210 int pageSize;
211 mib[0] = CTL_HW;
212 mib[1] = HW_PAGESIZE;
213 length = sizeof(int);
214 if (sysctl(mib, 2, &pageSize, &length, nullptr, 0) != 0)
215 return false;
216
217 uint64 usedMemory = static_cast<uint64>(vmStats.active_count +
218 vmStats.wire_count +
219 vmStats.compressor_page_count) * pageSize;
220 uint64 availableMemory = static_cast<uint64>(vmStats.free_count +
221 vmStats.inactive_count +
222 vmStats.speculative_count) * pageSize;
223
224 usage.usedPhysicalBytes = usedMemory;
225 usage.availablePhysicalBytes = availableMemory;
226
227 struct xsw_usage swapUsage;
228 mib[0] = CTL_VM;
229 mib[1] = VM_SWAPUSAGE;
230 length = sizeof(swapUsage);
231 if (sysctl(mib, 2, &swapUsage, &length, nullptr, 0) == 0)
232 {
233 usage.totalSwapBytes = swapUsage.xsu_total;
234 usage.usedSwapBytes = swapUsage.xsu_used;
235 }
236 else
237 {
238 usage.totalSwapBytes = 0;
239 usage.usedSwapBytes = 0;
240 }
241
242 usage.totalVirtualBytes = usage.totalPhysicalBytes + usage.totalSwapBytes;
243 usage.usedVirtualBytes = usage.usedPhysicalBytes + usage.usedSwapBytes;
244
245 if (usage.totalPhysicalBytes > 0)
246 {
247 usage.physicalUsagePercent = (static_cast<double>(usage.usedPhysicalBytes) /
248 static_cast<double>(usage.totalPhysicalBytes)) * 100.0;
249 }
250
251 if (usage.totalVirtualBytes > 0)
252 {
253 usage.virtualUsagePercent = (static_cast<double>(usage.usedVirtualBytes) /
254 static_cast<double>(usage.totalVirtualBytes)) * 100.0;
255 }
256
257 usage.hasValidData = true;
258 return true;
259
260#else
261 return false;
262#endif
263}
264
266{
267 char const* units[] = { "B", "KB", "MB", "GB", "TB" };
268 size_t unitIndex = 0;
269 double value = static_cast<double>(bytes);
270
271 while (value >= 1024.0 && unitIndex < (sizeof(units) / sizeof(units[0])) - 1)
272 {
273 value /= 1024.0;
274 ++unitIndex;
275 }
276
277 std::ostringstream stream;
278 if (unitIndex == 0)
279 stream << bytes << " B";
280 else
281 stream << std::fixed << std::setprecision(2) << value << ' ' << units[unitIndex];
282
283 return stream.str();
284}
285
287{
288 std::vector<std::string> fields;
289
290 if (usage.hasResidentBytes)
291 AppendMemoryField(fields, "RSS", usage.residentBytes);
292
293 if (usage.hasPrivateBytes)
294 AppendMemoryField(fields, "Private", usage.privateBytes);
295
296 if (usage.hasVirtualBytes)
297 AppendMemoryField(fields, "Virtual", usage.virtualBytes);
298
299 if (usage.hasPeakResidentBytes)
300 AppendMemoryField(fields, "Peak RSS", usage.peakResidentBytes);
301
302 if (fields.empty())
303 return "unavailable";
304
305 std::ostringstream stream;
306 for (size_t i = 0; i < fields.size(); ++i)
307 {
308 if (i != 0)
309 stream << ", ";
310
311 stream << fields[i];
312 }
313
314 return stream.str();
315}
316
318{
319 if (!usage.hasValidData)
320 return "System memory info unavailable";
321
322 std::vector<std::string> fields;
323
324 AppendMemoryField(fields, "Total RAM", usage.totalPhysicalBytes);
325 AppendMemoryField(fields, "Used RAM", usage.usedPhysicalBytes);
326 AppendMemoryField(fields, "Available RAM", usage.availablePhysicalBytes);
327 AppendPercentageField(fields, "RAM Usage", usage.physicalUsagePercent);
328
329 if (usage.totalSwapBytes > 0)
330 {
331 AppendMemoryField(fields, "Total Swap", usage.totalSwapBytes);
332 AppendMemoryField(fields, "Used Swap", usage.usedSwapBytes);
333 }
334
335 if (usage.totalVirtualBytes > 0)
336 {
337 AppendMemoryField(fields, "Total Virtual", usage.totalVirtualBytes);
338 AppendMemoryField(fields, "Used Virtual", usage.usedVirtualBytes);
339 AppendPercentageField(fields, "Virtual Usage", usage.virtualUsagePercent);
340 }
341
342 std::ostringstream stream;
343 for (size_t i = 0; i < fields.size(); ++i)
344 {
345 if (i != 0)
346 stream << ", ";
347
348 stream << fields[i];
349 }
350
351 return stream.str();
352}
353
355 SystemMemoryUsage const& systemUsage)
356{
357 std::ostringstream stream;
358
359 stream << "Process: " << FormatProcessMemoryUsage(processUsage);
360
361 if (systemUsage.hasValidData)
362 {
363 stream << " | System: ";
364 stream << "RAM " << std::fixed << std::setprecision(1)
365 << systemUsage.physicalUsagePercent << "% ";
366 stream << "(" << FormatMemorySize(systemUsage.usedPhysicalBytes) << "/"
367 << FormatMemorySize(systemUsage.totalPhysicalBytes) << ")";
368
369 if (systemUsage.totalSwapBytes > 0)
370 {
371 stream << ", Swap " << std::fixed << std::setprecision(1)
372 << ((systemUsage.totalSwapBytes > 0) ?
373 (static_cast<double>(systemUsage.usedSwapBytes) /
374 static_cast<double>(systemUsage.totalSwapBytes) * 100.0) : 0.0) << "%";
375 }
376 }
377 else
378 {
379 stream << " | System info unavailable";
380 }
381
382 return stream.str();
383}
std::uint64_t uint64
Definition Define.h:76
std::string FormatProcessMemoryUsage(ProcessMemoryUsage const &usage)
bool GetProcessMemoryUsage(ProcessMemoryUsage &usage)
std::string FormatMemorySize(uint64 bytes)
std::string FormatSystemMemoryUsage(SystemMemoryUsage const &usage)
bool GetSystemMemoryUsage(SystemMemoryUsage &usage)
std::string FormatMemoryUsageSummary(ProcessMemoryUsage const &processUsage, SystemMemoryUsage const &systemUsage)
void usage(const char *prog)
Print out the usage string for this program on the console.
Definition Main.cpp:192