From c899df9b5fcb886a123d03767981f01443129ff5 Mon Sep 17 00:00:00 2001 From: Roll249 <80768386+Roll249@users.noreply.github.com> Date: Sat, 31 May 2025 06:50:50 +0000 Subject: [PATCH 1/7] Implement cross-platform RAM capacity query in mem_tryGetLocalRamCapacityInBytes() for Linux, macOS, and Windows. Falls back to exception if not available. --- quest/src/core/memory.cpp | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/quest/src/core/memory.cpp b/quest/src/core/memory.cpp index 36eedb596..74d228598 100644 --- a/quest/src/core/memory.cpp +++ b/quest/src/core/memory.cpp @@ -196,11 +196,37 @@ qindex mem_getMaxNumKrausMapMatricesBeforeLocalMemSizeofOverflow(int numQubits) qindex mem_tryGetLocalRamCapacityInBytes() { - - /// @todo attempt to find total Ram - - // if we're unable to find total RAM, throw an exception - // (which the caller should catch and gracefully continue) + // Linux: parse /proc/meminfo + #if defined(__linux__) + FILE* meminfo = fopen("/proc/meminfo", "r"); + if (meminfo) { + char line[256]; + while (fgets(line, sizeof(line), meminfo)) { + if (sscanf(line, "MemTotal: %lu kB", &mem_total_kb) == 1) { + fclose(meminfo); + return (qindex)mem_total_kb * 1024; + } + } + fclose(meminfo); + } + // macOS: use sysctl + #elif defined(__APPLE__) + #include + #include + int mib[2] = {CTL_HW, HW_MEMSIZE}; + int64_t memsize = 0; + size_t len = sizeof(memsize); + if (sysctl(mib, 2, &memsize, &len, NULL, 0) == 0 && memsize > 0) + return (qindex)memsize; + // Windows: use GlobalMemoryStatusEx + #elif defined(_WIN32) + #include + MEMORYSTATUSEX statex; + statex.dwLength = sizeof(statex); + if (GlobalMemoryStatusEx(&statex)) + return (qindex)statex.ullTotalPhys; + #endif + // fallback: throw exception throw (mem::COULD_NOT_QUERY_RAM) false; } From 640120892e344ccfcb53447a5887380fdef56df8 Mon Sep 17 00:00:00 2001 From: Roll249 <80768386+Roll249@users.noreply.github.com> Date: Sat, 31 May 2025 06:51:45 +0000 Subject: [PATCH 2/7] add --- build/CMakeCache.txt | 53 ++++++++++++++++++++++++++++++ build/CMakeFiles/cmake.check_cache | 1 + 2 files changed, 54 insertions(+) create mode 100644 build/CMakeCache.txt create mode 100644 build/CMakeFiles/cmake.check_cache diff --git a/build/CMakeCache.txt b/build/CMakeCache.txt new file mode 100644 index 000000000..cea205a33 --- /dev/null +++ b/build/CMakeCache.txt @@ -0,0 +1,53 @@ +# This is the CMakeCache file. +# For build in directory: /workspaces/QuEST/build +# It was generated by CMake: /usr/bin/cmake +# You can edit this file to change values found and used by cmake. +# If you do not want to change any of the values, simply exit the editor. +# If you do want to change a value, simply edit, save, and exit the editor. +# The syntax for the file is as follows: +# KEY:TYPE=VALUE +# KEY is the name of a variable in the cache. +# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!. +# VALUE is the current value for the KEY. + +######################## +# EXTERNAL cache entries +######################## + + +######################## +# INTERNAL cache entries +######################## + +//This is the directory where this CMakeCache.txt was created +CMAKE_CACHEFILE_DIR:INTERNAL=/workspaces/QuEST/build +//Major version of cmake used to create the current loaded cache +CMAKE_CACHE_MAJOR_VERSION:INTERNAL=3 +//Minor version of cmake used to create the current loaded cache +CMAKE_CACHE_MINOR_VERSION:INTERNAL=16 +//Patch version of cmake used to create the current loaded cache +CMAKE_CACHE_PATCH_VERSION:INTERNAL=3 +//Path to CMake executable. +CMAKE_COMMAND:INTERNAL=/usr/bin/cmake +//Path to cpack program executable. +CMAKE_CPACK_COMMAND:INTERNAL=/usr/bin/cpack +//Path to ctest program executable. +CMAKE_CTEST_COMMAND:INTERNAL=/usr/bin/ctest +//Name of external makefile project generator. +CMAKE_EXTRA_GENERATOR:INTERNAL= +//Name of generator. +CMAKE_GENERATOR:INTERNAL=Unix Makefiles +//Generator instance identifier. +CMAKE_GENERATOR_INSTANCE:INTERNAL= +//Name of generator platform. +CMAKE_GENERATOR_PLATFORM:INTERNAL= +//Name of generator toolset. +CMAKE_GENERATOR_TOOLSET:INTERNAL= +//Source directory with the top level CMakeLists.txt file for this +// project +CMAKE_HOME_DIRECTORY:INTERNAL=/workspaces/QuEST +//number of local generators +CMAKE_NUMBER_OF_MAKEFILES:INTERNAL=1 +//Path to CMake installation. +CMAKE_ROOT:INTERNAL=/usr/share/cmake-3.16 + diff --git a/build/CMakeFiles/cmake.check_cache b/build/CMakeFiles/cmake.check_cache new file mode 100644 index 000000000..3dccd7317 --- /dev/null +++ b/build/CMakeFiles/cmake.check_cache @@ -0,0 +1 @@ +# This file is generated by cmake for dependency checking of the CMakeCache.txt file From fd6864833d1ae508ee45eca1ad556fcc6ceda91d Mon Sep 17 00:00:00 2001 From: Roll249 <80768386+Roll249@users.noreply.github.com> Date: Sat, 31 May 2025 16:03:29 +0000 Subject: [PATCH 3/7] Refactor mem_tryGetLocalRamCapacityInBytes: use sysinfo on Linux, move platform includes to top, improve clarity. Remove build/ from repo and add to .gitignore. --- .gitignore | 1 + build/CMakeCache.txt | 53 ------------------------------ build/CMakeFiles/cmake.check_cache | 1 - quest/src/core/memory.cpp | 48 +++++++++++++-------------- 4 files changed, 23 insertions(+), 80 deletions(-) create mode 100644 .gitignore delete mode 100644 build/CMakeCache.txt delete mode 100644 build/CMakeFiles/cmake.check_cache diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..567609b12 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/build/CMakeCache.txt b/build/CMakeCache.txt deleted file mode 100644 index cea205a33..000000000 --- a/build/CMakeCache.txt +++ /dev/null @@ -1,53 +0,0 @@ -# This is the CMakeCache file. -# For build in directory: /workspaces/QuEST/build -# It was generated by CMake: /usr/bin/cmake -# You can edit this file to change values found and used by cmake. -# If you do not want to change any of the values, simply exit the editor. -# If you do want to change a value, simply edit, save, and exit the editor. -# The syntax for the file is as follows: -# KEY:TYPE=VALUE -# KEY is the name of a variable in the cache. -# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!. -# VALUE is the current value for the KEY. - -######################## -# EXTERNAL cache entries -######################## - - -######################## -# INTERNAL cache entries -######################## - -//This is the directory where this CMakeCache.txt was created -CMAKE_CACHEFILE_DIR:INTERNAL=/workspaces/QuEST/build -//Major version of cmake used to create the current loaded cache -CMAKE_CACHE_MAJOR_VERSION:INTERNAL=3 -//Minor version of cmake used to create the current loaded cache -CMAKE_CACHE_MINOR_VERSION:INTERNAL=16 -//Patch version of cmake used to create the current loaded cache -CMAKE_CACHE_PATCH_VERSION:INTERNAL=3 -//Path to CMake executable. -CMAKE_COMMAND:INTERNAL=/usr/bin/cmake -//Path to cpack program executable. -CMAKE_CPACK_COMMAND:INTERNAL=/usr/bin/cpack -//Path to ctest program executable. -CMAKE_CTEST_COMMAND:INTERNAL=/usr/bin/ctest -//Name of external makefile project generator. -CMAKE_EXTRA_GENERATOR:INTERNAL= -//Name of generator. -CMAKE_GENERATOR:INTERNAL=Unix Makefiles -//Generator instance identifier. -CMAKE_GENERATOR_INSTANCE:INTERNAL= -//Name of generator platform. -CMAKE_GENERATOR_PLATFORM:INTERNAL= -//Name of generator toolset. -CMAKE_GENERATOR_TOOLSET:INTERNAL= -//Source directory with the top level CMakeLists.txt file for this -// project -CMAKE_HOME_DIRECTORY:INTERNAL=/workspaces/QuEST -//number of local generators -CMAKE_NUMBER_OF_MAKEFILES:INTERNAL=1 -//Path to CMake installation. -CMAKE_ROOT:INTERNAL=/usr/share/cmake-3.16 - diff --git a/build/CMakeFiles/cmake.check_cache b/build/CMakeFiles/cmake.check_cache deleted file mode 100644 index 3dccd7317..000000000 --- a/build/CMakeFiles/cmake.check_cache +++ /dev/null @@ -1 +0,0 @@ -# This file is generated by cmake for dependency checking of the CMakeCache.txt file diff --git a/quest/src/core/memory.cpp b/quest/src/core/memory.cpp index 74d228598..07de5bde2 100644 --- a/quest/src/core/memory.cpp +++ b/quest/src/core/memory.cpp @@ -21,6 +21,16 @@ #include +// Platform-specific includes for RAM querying +#if defined(__linux__) + #include +#elif defined(__APPLE__) + #include + #include +#elif defined(_WIN32) + #include +#endif + /* @@ -196,35 +206,21 @@ qindex mem_getMaxNumKrausMapMatricesBeforeLocalMemSizeofOverflow(int numQubits) qindex mem_tryGetLocalRamCapacityInBytes() { - // Linux: parse /proc/meminfo #if defined(__linux__) - FILE* meminfo = fopen("/proc/meminfo", "r"); - if (meminfo) { - char line[256]; - while (fgets(line, sizeof(line), meminfo)) { - if (sscanf(line, "MemTotal: %lu kB", &mem_total_kb) == 1) { - fclose(meminfo); - return (qindex)mem_total_kb * 1024; - } - } - fclose(meminfo); - } - // macOS: use sysctl + struct sysinfo info; + if (sysinfo(&info) == 0) + return (qindex) info.totalram * info.mem_unit; #elif defined(__APPLE__) - #include - #include - int mib[2] = {CTL_HW, HW_MEMSIZE}; - int64_t memsize = 0; - size_t len = sizeof(memsize); - if (sysctl(mib, 2, &memsize, &len, NULL, 0) == 0 && memsize > 0) - return (qindex)memsize; - // Windows: use GlobalMemoryStatusEx + int mib[2] = {CTL_HW, HW_MEMSIZE}; + int64_t memsize = 0; + size_t len = sizeof(memsize); + if (sysctl(mib, 2, &memsize, &len, NULL, 0) == 0 && memsize > 0) + return (qindex) memsize; #elif defined(_WIN32) - #include - MEMORYSTATUSEX statex; - statex.dwLength = sizeof(statex); - if (GlobalMemoryStatusEx(&statex)) - return (qindex)statex.ullTotalPhys; + MEMORYSTATUSEX statex; + statex.dwLength = sizeof(statex); + if (GlobalMemoryStatusEx(&statex)) + return (qindex) statex.ullTotalPhys; #endif // fallback: throw exception throw (mem::COULD_NOT_QUERY_RAM) false; From ba0b6bae225b7b9ccd61b9763d0239c67425d2de Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sat, 31 May 2025 19:31:27 +0200 Subject: [PATCH 4/7] test patch for MSVC since the windows.h header otherwise defines a `min` and `max` macro which interferes with the existing functions used in this file --- quest/src/core/memory.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/quest/src/core/memory.cpp b/quest/src/core/memory.cpp index 07de5bde2..fc2a4c39c 100644 --- a/quest/src/core/memory.cpp +++ b/quest/src/core/memory.cpp @@ -28,6 +28,7 @@ #include #include #elif defined(_WIN32) + #define NOMINMAX #include #endif From 58117a173d067b9bec358a70f80a0bafae6fc7f2 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sat, 31 May 2025 19:40:52 +0200 Subject: [PATCH 5/7] deleted .gitignore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit it's faster to just do it myself ¯\_(ツ)_/¯ --- .gitignore | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .gitignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 567609b12..000000000 --- a/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/ From b08a50420b7ee7f1242ebd974ec6b0f6eb3a7fb7 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Tue, 3 Jun 2025 16:40:21 +0200 Subject: [PATCH 6/7] updated test validation messages --- tests/unit/channels.cpp | 12 ++++++++++-- tests/unit/matrices.cpp | 24 ++++++++++++++++++++---- tests/unit/qureg.cpp | 36 ++++++++++++++++++++++++++++++------ 3 files changed, 60 insertions(+), 12 deletions(-) diff --git a/tests/unit/channels.cpp b/tests/unit/channels.cpp index b0a7ab314..e068368c5 100644 --- a/tests/unit/channels.cpp +++ b/tests/unit/channels.cpp @@ -126,7 +126,11 @@ TEST_CASE( "createKrausMap", TEST_CATEGORY ) { // GPU-accel or distributed) and whether memory-probers realised there was insufficient memory in // advance or whether it proceeded to malloc() which subsequently failed #ifndef SANITIZER_IS_ACTIVE - REQUIRE_THROWS_WITH( createKrausMap(12,1), ContainsSubstring("failed") || ContainsSubstring("insufficient available memory") || ContainsSubstring("available GPU memory") ); + REQUIRE_THROWS_WITH( createKrausMap(12,1), + ContainsSubstring("failed") || + ContainsSubstring("insufficient available memory") || + ContainsSubstring("exceeds the available memory") || + ContainsSubstring("available GPU memory") ); #endif } @@ -512,7 +516,11 @@ TEST_CASE( "createSuperOp", TEST_CATEGORY ) { // GPU-accel or distributed) and whether memory-probers realised there was insufficient memory in // advance or whether it proceeded to malloc() which subsequently failed #ifndef SANITIZER_IS_ACTIVE - REQUIRE_THROWS_WITH( createSuperOp(12), ContainsSubstring("failed") || ContainsSubstring("insufficient available memory") || ContainsSubstring("available GPU memory") ); + REQUIRE_THROWS_WITH( createSuperOp(12), + ContainsSubstring("failed") || + ContainsSubstring("insufficient available memory") || + ContainsSubstring("available GPU memory") || + ContainsSubstring("exceeds that available") ); #endif } } diff --git a/tests/unit/matrices.cpp b/tests/unit/matrices.cpp index 591e3bc7b..ef92dbcda 100644 --- a/tests/unit/matrices.cpp +++ b/tests/unit/matrices.cpp @@ -456,7 +456,11 @@ TEST_CASE( "createCompMatr", TEST_CATEGORY ) { // GPU-accel or distributed) and whether memory-probers realised there was insufficient memory in // advance or whether it proceeded to malloc() which subsequently failed #ifndef SANITIZER_IS_ACTIVE - REQUIRE_THROWS_WITH( createCompMatr(25), ContainsSubstring("failed") || ContainsSubstring("insufficient available memory") || ContainsSubstring("available GPU memory") ); + REQUIRE_THROWS_WITH( createCompMatr(25), + ContainsSubstring("failed") || + ContainsSubstring("insufficient available memory") || + ContainsSubstring("available GPU memory") || + ContainsSubstring("exceeds the available RAM") ); #endif } } @@ -529,7 +533,11 @@ TEST_CASE( "createDiagMatr", TEST_CATEGORY ) { // GPU-accel or distributed) and whether memory-probers realised there was insufficient memory in // advance or whether it proceeded to malloc() which subsequently failed #ifndef SANITIZER_IS_ACTIVE - REQUIRE_THROWS_WITH( createDiagMatr(50), ContainsSubstring("failed") || ContainsSubstring("insufficient available memory") || ContainsSubstring("available GPU memory") ); + REQUIRE_THROWS_WITH( createDiagMatr(50), + ContainsSubstring("failed") || + ContainsSubstring("insufficient available memory") || + ContainsSubstring("available GPU memory") || + ContainsSubstring("exceeds the available RAM") ); #endif } } @@ -602,7 +610,11 @@ TEST_CASE( "createFullStateDiagMatr", TEST_CATEGORY ) { // GPU-accel or distributed) and whether memory-probers realised there was insufficient memory in // advance or whether it proceeded to malloc() which subsequently failed #ifndef SANITIZER_IS_ACTIVE - REQUIRE_THROWS_WITH( createFullStateDiagMatr(50), ContainsSubstring("failed") || ContainsSubstring("insufficient available memory") || ContainsSubstring("available GPU memory") ); + REQUIRE_THROWS_WITH( createFullStateDiagMatr(50), + ContainsSubstring("failed") || + ContainsSubstring("insufficient available memory") || + ContainsSubstring("available GPU memory") || + ContainsSubstring("exceeds the available RAM") ); #endif } @@ -698,7 +710,11 @@ TEST_CASE( "createCustomFullStateDiagMatr", TEST_CATEGORY ) { // GPU-accel or distributed) and whether memory-probers realised there was insufficient memory in // advance or whether it proceeded to malloc() which subsequently failed #ifndef SANITIZER_IS_ACTIVE - REQUIRE_THROWS_WITH( createCustomFullStateDiagMatr(50, mpi,gpu,omp), ContainsSubstring("failed") || ContainsSubstring("insufficient available memory") || ContainsSubstring("available GPU memory") ); + REQUIRE_THROWS_WITH( createCustomFullStateDiagMatr(50, mpi,gpu,omp), + ContainsSubstring("failed") || + ContainsSubstring("insufficient available memory") || + ContainsSubstring("available GPU memory") || + ContainsSubstring("exceeds the available RAM") ); #endif } } diff --git a/tests/unit/qureg.cpp b/tests/unit/qureg.cpp index aaf3bb0cd..4b2b46311 100644 --- a/tests/unit/qureg.cpp +++ b/tests/unit/qureg.cpp @@ -125,7 +125,11 @@ TEST_CASE( "createQureg", TEST_CATEGORY ) { // GPU-accel or distributed) and whether memory-probers realised there was insufficient memory in // advance or whether it proceeded to malloc() which subsequently failed #ifndef SANITIZER_IS_ACTIVE - REQUIRE_THROWS_WITH( createQureg(50), ContainsSubstring("failed") || ContainsSubstring("insufficient available memory") || ContainsSubstring("available GPU memory") ); + REQUIRE_THROWS_WITH( createQureg(50), + ContainsSubstring("failed") || + ContainsSubstring("insufficient available memory") || + ContainsSubstring("available GPU memory") || + ContainsSubstring("RAM") ); #endif } } @@ -210,7 +214,11 @@ TEST_CASE( "createDensityQureg", TEST_CATEGORY ) { // GPU-accel or distributed) and whether memory-probers realised there was insufficient memory in // advance or whether it proceeded to malloc() which subsequently failed #ifndef SANITIZER_IS_ACTIVE - REQUIRE_THROWS_WITH( createDensityQureg(25), ContainsSubstring("failed") || ContainsSubstring("insufficient available memory") || ContainsSubstring("available GPU memory") ); + REQUIRE_THROWS_WITH( createDensityQureg(25), + ContainsSubstring("failed") || + ContainsSubstring("insufficient available memory") || + ContainsSubstring("available GPU memory") || + ContainsSubstring("RAM") ); #endif } } @@ -302,7 +310,11 @@ TEST_CASE( "createForcedQureg", TEST_CATEGORY ) { // GPU-accel or distributed) and whether memory-probers realised there was insufficient memory in // advance or whether it proceeded to malloc() which subsequently failed #ifndef SANITIZER_IS_ACTIVE - REQUIRE_THROWS_WITH( createForcedQureg(50), ContainsSubstring("failed") || ContainsSubstring("insufficient available memory") || ContainsSubstring("available GPU memory") ); + REQUIRE_THROWS_WITH( createForcedQureg(50), + ContainsSubstring("failed") || + ContainsSubstring("insufficient available memory") || + ContainsSubstring("available GPU memory") || + ContainsSubstring("RAM") ); #endif } } @@ -395,7 +407,11 @@ TEST_CASE( "createForcedDensityQureg", TEST_CATEGORY ) { // GPU-accel or distributed) and whether memory-probers realised there was insufficient memory in // advance or whether it proceeded to malloc() which subsequently failed #ifndef SANITIZER_IS_ACTIVE - REQUIRE_THROWS_WITH( createForcedDensityQureg(25), ContainsSubstring("failed") || ContainsSubstring("insufficient available memory") || ContainsSubstring("available GPU memory") ); + REQUIRE_THROWS_WITH( createForcedDensityQureg(25), + ContainsSubstring("failed") || + ContainsSubstring("insufficient available memory") || + ContainsSubstring("available GPU memory") || + ContainsSubstring("RAM") ); #endif } } @@ -531,8 +547,16 @@ TEST_CASE( "createCustomQureg", TEST_CATEGORY ) { // GPU-accel or distributed) and whether memory-probers realised there was insufficient memory in // advance or whether it proceeded to malloc() which subsequently failed #ifndef SANITIZER_IS_ACTIVE - REQUIRE_THROWS_WITH( createCustomQureg(50, 0, 0,0,0), ContainsSubstring("failed") || ContainsSubstring("insufficient available memory") || ContainsSubstring("available GPU memory") ); - REQUIRE_THROWS_WITH( createCustomQureg(25, 1, 0,0,0), ContainsSubstring("failed") || ContainsSubstring("insufficient available memory") || ContainsSubstring("available GPU memory") ); + REQUIRE_THROWS_WITH( createCustomQureg(50, 0, 0,0,0), + ContainsSubstring("failed") || + ContainsSubstring("insufficient available memory") || + ContainsSubstring("available GPU memory") || + ContainsSubstring("RAM") ); + REQUIRE_THROWS_WITH( createCustomQureg(25, 1, 0,0,0), + ContainsSubstring("failed") || + ContainsSubstring("insufficient available memory") || + ContainsSubstring("available GPU memory") || + ContainsSubstring("RAM") ); #endif } } From 15e24310e2b808f22c486ef3072ad62b54c76994 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Tue, 3 Jun 2025 16:46:57 +0200 Subject: [PATCH 7/7] added Mai (Roll249) to authorlist --- AUTHORS.txt | 2 ++ README.md | 1 + 2 files changed, 3 insertions(+) diff --git a/AUTHORS.txt b/AUTHORS.txt index 5b2cdd084..33ca79a1c 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -44,6 +44,8 @@ Dr Ian Bush [consultant] HPC External contributors: +Mai Đức Khang + implemented RAM probe (for unitaryHACK issue #600) James Richings patched overflow in bitwise.hpp logic Luc Jaulmes diff --git a/README.md b/README.md index 260d4b8bb..9e05597a2 100644 --- a/README.md +++ b/README.md @@ -257,6 +257,7 @@ See the [docs](docs/README.md) for enabling acceleration and running the unit te In addition to QuEST's [authors](AUTHORS.txt), we sincerely thank the following external contributors to QuEST. +- [Mai Đức Khang](https://github.com/Roll249) for implementing a RAM probe (unitaryHACK 2025 [#600](https://github.com/QuEST-Kit/QuEST/issues/600)). - [James Richings](https://github.com/JPRichings) for patching a v4 overflow bug. - [Luc Jaulmes](https://github.com/lucjaulmes) for patching v4's CMake installation. - [Jakub Adamski](https://github.com/jjacobx) for optimising distributed communication of max-size messages.