diff --git a/src/common/system.cpp b/src/common/system.cpp index 7af792db44c..cf032adfced 100644 --- a/src/common/system.cpp +++ b/src/common/system.cpp @@ -11,19 +11,25 @@ #include #include -#ifndef WIN32 -#include -#else -#include +#ifdef WIN32 #include +#include +#include +#else +#include +#include #endif #ifdef HAVE_MALLOPT_ARENA_MAX #include #endif +#include +#include +#include #include #include +#include #include #include #include @@ -105,6 +111,17 @@ int GetNumCores() return std::thread::hardware_concurrency(); } +std::optional GetTotalRAM() +{ + auto clamp{[](uint64_t v) { return size_t(std::min(v, uint64_t{std::numeric_limits::max()})); }}; +#ifdef WIN32 + if (MEMORYSTATUSEX m{}; (m.dwLength = sizeof(m), GlobalMemoryStatusEx(&m))) return clamp(m.ullTotalPhys); +#elif defined(__linux__) || defined(__APPLE__) + if (long p{sysconf(_SC_PHYS_PAGES)}, s{sysconf(_SC_PAGESIZE)}; p > 0 && s > 0) return clamp(1ULL * p * s); +#endif + return std::nullopt; +} + // Obtain the application startup time (used for uptime calculation) int64_t GetStartupTime() { diff --git a/src/common/system.h b/src/common/system.h index a4b56be9ac9..2184f1d4c9e 100644 --- a/src/common/system.h +++ b/src/common/system.h @@ -9,6 +9,7 @@ #include // IWYU pragma: keep #include +#include #include // Application startup time (used for uptime calculation) @@ -29,4 +30,9 @@ void runCommand(const std::string& strCommand); */ int GetNumCores(); +/** + * Return the total RAM available on the current system, if detectable. + */ +std::optional GetTotalRAM(); + #endif // BITCOIN_COMMON_SYSTEM_H diff --git a/src/test/system_tests.cpp b/src/test/system_tests.cpp index dec4d418290..53db32007ee 100644 --- a/src/test/system_tests.cpp +++ b/src/test/system_tests.cpp @@ -8,6 +8,8 @@ #include #include +#include + #ifdef ENABLE_EXTERNAL_SIGNER #include #endif // ENABLE_EXTERNAL_SIGNER @@ -16,6 +18,17 @@ BOOST_FIXTURE_TEST_SUITE(system_tests, BasicTestingSetup) +BOOST_AUTO_TEST_CASE(total_ram) +{ + BOOST_CHECK_GE(GetTotalRAM(), 1000_MiB); + + if constexpr (SIZE_MAX == UINT64_MAX) { + // Upper bound check only on 64-bit: 32-bit systems can reasonably have max memory, + // but extremely large values on 64-bit likely indicate detection errors + BOOST_CHECK_LT(GetTotalRAM(), 10'000'000_MiB); // >10 TiB memory is unlikely + } +} + #ifdef ENABLE_EXTERNAL_SIGNER BOOST_AUTO_TEST_CASE(run_command)