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. diff --git a/quest/src/core/memory.cpp b/quest/src/core/memory.cpp index 36eedb596..fc2a4c39c 100644 --- a/quest/src/core/memory.cpp +++ b/quest/src/core/memory.cpp @@ -21,6 +21,17 @@ #include +// Platform-specific includes for RAM querying +#if defined(__linux__) + #include +#elif defined(__APPLE__) + #include + #include +#elif defined(_WIN32) + #define NOMINMAX + #include +#endif + /* @@ -196,11 +207,23 @@ 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) + #if defined(__linux__) + struct sysinfo info; + if (sysinfo(&info) == 0) + return (qindex) info.totalram * info.mem_unit; + #elif defined(__APPLE__) + 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) + MEMORYSTATUSEX statex; + statex.dwLength = sizeof(statex); + if (GlobalMemoryStatusEx(&statex)) + return (qindex) statex.ullTotalPhys; + #endif + // fallback: throw exception throw (mem::COULD_NOT_QUERY_RAM) false; } 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 } }