Skip to content

Commit 5764cfd

Browse files
imikejacksonclaude
andcommitted
ENH: Add GetSystemMemoryInfo() to MemoryUtilities
Extend nx::core::Memory with a SystemMemoryInfo struct and GetSystemMemoryInfo() function that returns a cross-platform snapshot of: - totalGB — total installed physical RAM - usedGB — currently used RAM (total - available) - loadPercent — system memory load percentage - processGB — resident memory of the current process Platform implementations: - Windows: GlobalMemoryStatusEx + GetProcessMemoryInfo (WorkingSetSize) - macOS: hw.memsize sysctl, HOST_VM_INFO64 vm_statistics, TASK_VM_INFO phys_footprint - Linux: /proc/meminfo (free-command formula) + /proc/self/statm No Qt dependency; pure C++ / OS headers only. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
1 parent 021a4f7 commit 5764cfd

File tree

2 files changed

+218
-2
lines changed

2 files changed

+218
-2
lines changed

src/simplnx/Utilities/MemoryUtilities.cpp

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,15 @@
33
#if defined(_WIN32)
44
#include <cstdlib>
55
#include <windows.h>
6+
7+
#include <psapi.h>
8+
#elif defined(__APPLE__)
9+
#include <mach/mach.h>
10+
#include <sys/sysctl.h>
11+
#include <unistd.h>
612
#else
13+
#include <fstream>
14+
#include <sstream>
715
#include <unistd.h>
816
#endif
917

@@ -59,4 +67,155 @@ dataStorage GetAvailableStorageOnDrive(const std::filesystem::path& directory)
5967
return storage;
6068
}
6169
#endif
70+
71+
// =============================================================================
72+
// GetSystemMemoryInfo — platform implementations
73+
// =============================================================================
74+
75+
#if defined(_WIN32)
76+
77+
SystemMemoryInfo GetSystemMemoryInfo()
78+
{
79+
SystemMemoryInfo info;
80+
81+
MEMORYSTATUSEX memStatus;
82+
memStatus.dwLength = sizeof(MEMORYSTATUSEX);
83+
if(GlobalMemoryStatusEx(&memStatus))
84+
{
85+
info.totalGB = static_cast<double>(memStatus.ullTotalPhys) / (1024.0 * 1024.0 * 1024.0);
86+
const double availableGB = static_cast<double>(memStatus.ullAvailPhys) / (1024.0 * 1024.0 * 1024.0);
87+
info.usedGB = info.totalGB - availableGB;
88+
info.loadPercent = static_cast<double>(memStatus.dwMemoryLoad);
89+
}
90+
91+
PROCESS_MEMORY_COUNTERS_EX pmc;
92+
const HANDLE hProcess = GetCurrentProcess();
93+
if(GetProcessMemoryInfo(hProcess, reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmc), sizeof(pmc)))
94+
{
95+
info.processGB = static_cast<double>(pmc.WorkingSetSize) / (1024.0 * 1024.0 * 1024.0);
96+
}
97+
98+
return info;
99+
}
100+
101+
#elif defined(__APPLE__)
102+
103+
namespace
104+
{
105+
// Helper: read a 64-bit integer sysctl value by name.
106+
int sysctlInt64(const char* name, int64_t* value)
107+
{
108+
size_t len = sizeof(int64_t);
109+
return sysctlbyname(name, value, &len, nullptr, 0);
110+
}
111+
} // namespace
112+
113+
SystemMemoryInfo GetSystemMemoryInfo()
114+
{
115+
SystemMemoryInfo info;
116+
117+
int64_t tempInt64 = 0;
118+
119+
if(sysctlInt64("hw.memsize", &tempInt64) != 0)
120+
{
121+
return info;
122+
}
123+
info.totalGB = static_cast<double>(tempInt64) / (1024.0 * 1024.0 * 1024.0);
124+
125+
vm_statistics64_data_t vmstat;
126+
mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
127+
if(host_statistics64(mach_host_self(), HOST_VM_INFO64, reinterpret_cast<host_info64_t>(&vmstat), &count) == KERN_SUCCESS)
128+
{
129+
if(sysctlInt64("hw.pagesize", &tempInt64) == 0)
130+
{
131+
const int64_t availableBytes = (static_cast<int64_t>(vmstat.free_count) + static_cast<int64_t>(vmstat.inactive_count)) * tempInt64;
132+
const double availableGB = static_cast<double>(availableBytes) / (1024.0 * 1024.0 * 1024.0);
133+
info.usedGB = info.totalGB - availableGB;
134+
if(info.totalGB > 0.0)
135+
{
136+
info.loadPercent = info.usedGB * 100.0 / info.totalGB;
137+
}
138+
}
139+
}
140+
141+
task_vm_info_data_t taskInfo;
142+
mach_msg_type_number_t taskCount = TASK_VM_INFO_COUNT;
143+
if(task_info(mach_task_self(), TASK_VM_INFO, reinterpret_cast<task_info_t>(&taskInfo), &taskCount) == KERN_SUCCESS)
144+
{
145+
info.processGB = static_cast<double>(taskInfo.phys_footprint) / (1024.0 * 1024.0 * 1024.0);
146+
}
147+
148+
return info;
149+
}
150+
151+
#else // Linux
152+
153+
SystemMemoryInfo GetSystemMemoryInfo()
154+
{
155+
SystemMemoryInfo info;
156+
157+
// Parse /proc/meminfo for system-wide memory figures
158+
{
159+
std::ifstream file("/proc/meminfo");
160+
if(!file.is_open())
161+
{
162+
return info;
163+
}
164+
165+
uint64_t memTotal = 0;
166+
uint64_t memFree = 0;
167+
uint64_t buffers = 0;
168+
uint64_t cached = 0;
169+
uint64_t sReclaimable = 0;
170+
171+
std::string line;
172+
while(std::getline(file, line))
173+
{
174+
std::istringstream iss(line);
175+
std::string key;
176+
uint64_t value = 0;
177+
std::string unit;
178+
iss >> key >> value >> unit;
179+
180+
if(key == "MemTotal:")
181+
memTotal = value;
182+
else if(key == "MemFree:")
183+
memFree = value;
184+
else if(key == "Buffers:")
185+
buffers = value;
186+
else if(key == "Cached:")
187+
cached = value;
188+
else if(key == "SReclaimable:")
189+
sReclaimable = value;
190+
}
191+
192+
// Match the 'used' calculation from the 'free' command:
193+
// used = total - (free + buffers + cached + SReclaimable)
194+
const uint64_t usedKB = memTotal - (memFree + buffers + cached + sReclaimable);
195+
info.totalGB = static_cast<double>(memTotal) / (1024.0 * 1024.0);
196+
info.usedGB = static_cast<double>(usedKB) / (1024.0 * 1024.0);
197+
if(info.totalGB > 0.0)
198+
{
199+
info.loadPercent = info.usedGB * 100.0 / info.totalGB;
200+
}
201+
}
202+
203+
// Read current process resident set size from /proc/self/statm
204+
{
205+
std::ifstream statm("/proc/self/statm");
206+
if(statm.is_open())
207+
{
208+
unsigned long long totalPages = 0;
209+
unsigned long long residentPages = 0;
210+
statm >> totalPages >> residentPages;
211+
const long pageSizeBytes = sysconf(_SC_PAGESIZE);
212+
info.processGB = static_cast<double>(residentPages) * static_cast<double>(pageSizeBytes) / (1024.0 * 1024.0 * 1024.0);
213+
}
214+
}
215+
216+
return info;
217+
}
218+
219+
#endif
220+
62221
} // namespace nx::core::Memory

src/simplnx/Utilities/MemoryUtilities.hpp

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,71 @@ namespace nx::core
99
{
1010
namespace Memory
1111
{
12+
13+
/**
14+
* @brief Holds a total capacity and free-space measurement for a storage
15+
* device or filesystem, in bytes.
16+
*/
1217
struct SIMPLNX_EXPORT dataStorage
1318
{
14-
uint64_t total = 0;
15-
uint64_t free = 0;
19+
uint64_t total = 0; ///< Total capacity of the storage device in bytes.
20+
uint64_t free = 0; ///< Available (free) space on the storage device in bytes.
1621
};
1722

23+
/**
24+
* @brief Returns the total amount of physical RAM installed in the system.
25+
*
26+
* @return Total physical memory in bytes.
27+
*/
1828
uint64 SIMPLNX_EXPORT GetTotalMemory();
29+
30+
/**
31+
* @brief Returns the total and free space on the default temporary storage
32+
* device (equivalent to calling GetAvailableStorageOnDrive() with the
33+
* platform's temporary directory path).
34+
*
35+
* @return dataStorage containing total and free bytes on the temp drive.
36+
* @see GetAvailableStorageOnDrive()
37+
*/
1938
dataStorage SIMPLNX_EXPORT GetAvailableStorage();
39+
40+
/**
41+
* @brief Returns the total and free space on the filesystem that contains
42+
* @p path.
43+
*
44+
* @param path Any path that resides on the drive or filesystem to query.
45+
* On Windows this determines the drive letter; on POSIX systems
46+
* it determines the mount point.
47+
* @return dataStorage containing total and free bytes on the queried drive.
48+
* @see GetAvailableStorage()
49+
*/
2050
dataStorage SIMPLNX_EXPORT GetAvailableStorageOnDrive(const std::filesystem::path& path);
51+
52+
/**
53+
* @brief Snapshot of system-wide and per-process memory statistics.
54+
*
55+
* All memory quantities are expressed in gigabytes (GB).
56+
*/
57+
struct SIMPLNX_EXPORT SystemMemoryInfo
58+
{
59+
double totalGB = 0.0; ///< Total installed physical RAM in GB.
60+
double usedGB = 0.0; ///< Currently used physical RAM in GB (total - available).
61+
double loadPercent = 0.0; ///< System memory load as a percentage in the range [0, 100].
62+
double processGB = 0.0; ///< Resident memory used by the current process in GB.
63+
};
64+
65+
/**
66+
* @brief Query the operating system for a current snapshot of system and
67+
* process memory usage.
68+
*
69+
* Supported platforms: Windows, macOS, Linux (/proc/meminfo).
70+
* Returns a zero-initialised struct on any platform error.
71+
*
72+
* @return SystemMemoryInfo containing total RAM, used RAM, memory load
73+
* percentage, and the calling process's resident memory.
74+
* @see SystemMemoryInfo
75+
*/
76+
SIMPLNX_EXPORT SystemMemoryInfo GetSystemMemoryInfo();
77+
2178
} // namespace Memory
2279
} // namespace nx::core

0 commit comments

Comments
 (0)