Skip to content

Commit 2e2c703

Browse files
committed
io: Skip large collection test when not enough memory
1 parent 653cf96 commit 2e2c703

3 files changed

Lines changed: 70 additions & 2 deletions

File tree

cmake/modules/RootTestDriver.cmake

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,12 @@ endif()
132132
#---Execute pre-command-----------------------------------------------------------------------------
133133
if(PRE)
134134
execute_process(COMMAND ${_pre} ${_cwd} RESULT_VARIABLE _rc)
135-
if(_rc)
135+
if(_rc EQUAL 77)
136+
# Exit code 77 from a pre-command means "skip this test".
137+
# Print a sentinel recognised by SKIP_REGULAR_EXPRESSION on the test.
138+
message(STATUS "ROOTTEST_SKIP: pre-command requested skip -- skipping test")
139+
return()
140+
elseif(_rc)
136141
message(FATAL_ERROR "pre-command error code : ${_rc}")
137142
endif()
138143
endif()

io/io/test/CMakeLists.txt

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,52 @@ if(NOT _32BIT)
6666
ROOTTEST_COMPILE_MACRO(testLargeCollection.cxx
6767
FIXTURES_SETUP io-io-testcoll-fixture)
6868

69+
# Memory-check script: exits 0 when enough RAM+swap is available, 77 (skip) otherwise.
70+
# RootTestDriver.cmake propagates exit code 77 from PRECMD to the test's own exit code,
71+
# and SKIP_RETURN_CODE 77 on the main test turns that into a proper CTest "Skipped".
72+
set(_memcheck_script "${CMAKE_CURRENT_BINARY_DIR}/check_mem_for_large_coll.sh")
73+
file(WRITE ${_memcheck_script}
74+
"#!/bin/sh\n"
75+
"# Exit 77 (CTest SKIP via SKIP_RETURN_CODE) if total RAM+swap < 32 GB.\n"
76+
"# We use TOTAL (not free) because the OS reclaims cached pages on demand.\n"
77+
"THRESHOLD_KB=33554432\n"
78+
"if [ -r /proc/meminfo ]; then\n"
79+
" # Linux: use MemTotal + SwapTotal (kernel will reclaim caches as needed)\n"
80+
" RAM_KB=\$(awk '/^MemTotal:/{print \$2}' /proc/meminfo)\n"
81+
" SWAP_KB=\$(awk '/^SwapTotal:/{print \$2}' /proc/meminfo)\n"
82+
" RAM_KB=\${RAM_KB:-0}\n"
83+
" SWAP_KB=\${SWAP_KB:-0}\n"
84+
" TOTAL_KB=\$(( RAM_KB + SWAP_KB ))\n"
85+
"elif [ \"\$(uname)\" = \"Darwin\" ]; then\n"
86+
" # macOS: total physical RAM via sysctl hw.memsize (bytes -> kB)\n"
87+
" RAM_BYTES=\$(sysctl -n hw.memsize 2>/dev/null)\n"
88+
" RAM_KB=\$(( \${RAM_BYTES:-0} / 1024 ))\n"
89+
" # sysctl output: 'total = NNN.NNM used = ... free = ...'\n"
90+
" SWAP_TOTAL_MB=\$(sysctl -n vm.swapusage 2>/dev/null | sed 's/total = \\([0-9.]*\\)M.*/\\1/')\n"
91+
" if [ -n \"\$SWAP_TOTAL_MB\" ]; then\n"
92+
" SWAP_KB=\$(awk \"BEGIN{printf \\\"%d\\\", \$SWAP_TOTAL_MB * 1024}\")\n"
93+
" else\n"
94+
" SWAP_KB=0\n"
95+
" fi\n"
96+
" TOTAL_KB=\$(( RAM_KB + SWAP_KB ))\n"
97+
"else\n"
98+
" echo \"testLargeCollections memory check: unsupported OS, assuming enough memory\"\n"
99+
" exit 0\n"
100+
"fi\n"
101+
"echo \"testLargeCollections memory check: total \${TOTAL_KB} kB (RAM \${RAM_KB} + swap \${SWAP_KB}), need \${THRESHOLD_KB} kB\"\n"
102+
"if [ \"\$TOTAL_KB\" -lt \"\$THRESHOLD_KB\" ]; then\n"
103+
" echo \"Insufficient memory -- skipping testLargeCollections\"\n"
104+
" exit 77\n"
105+
"fi\n"
106+
"exit 0\n"
107+
)
108+
execute_process(COMMAND chmod +x ${_memcheck_script})
109+
69110
ROOTTEST_ADD_TEST(testLargeCollections
70111
TIMEOUT 1200
71112
MACRO testLargeCollection.cxx+
72113
OUTREF testLargeCollection.ref
73-
FIXTURES_REQUIRED io-io-testcoll-fixture)
114+
FIXTURES_REQUIRED io-io-testcoll-fixture
115+
PRECMD sh ${_memcheck_script}
116+
PROPERTIES "SKIP_REGULAR_EXPRESSION;ROOTTEST_SKIP")
74117
endif()

io/io/test/testLargeCollection.cxx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,32 @@
1616
#include <iostream>
1717
#include <limits>
1818
#include <vector>
19+
#if !defined(_WIN32)
1920
#include <sys/resource.h>
21+
#endif
2022
#if defined(__APPLE__)
2123
#include <sys/sysctl.h>
2224
#elif defined(__linux__)
2325
#include <sys/sysinfo.h>
2426
#elif defined(_WIN32)
27+
#ifndef WIN32_LEAN_AND_MEAN
28+
#define WIN32_LEAN_AND_MEAN
29+
#endif
30+
#ifndef NOMINMAX
31+
#define NOMINMAX
32+
#endif
2533
#include <windows.h>
34+
#include <psapi.h>
2635
#endif
2736

2837
// Timing helper — writes to a dedicated file, not captured by the ctest driver.
2938
static std::ofstream &timingLog()
3039
{
40+
#if defined(_WIN32)
41+
static std::ofstream f("testLargeCollection_timing.txt");
42+
#else
3143
static std::ofstream f("/tmp/testLargeCollection_timing.txt");
44+
#endif
3245
return f;
3346
}
3447
static double now_sec()
@@ -41,13 +54,20 @@ static double now_sec()
4154
// ru_maxrss is bytes on macOS, kilobytes on Linux.
4255
static double peak_rss_mb()
4356
{
57+
#if defined(_WIN32)
58+
PROCESS_MEMORY_COUNTERS pmc;
59+
if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))
60+
return pmc.PeakWorkingSetSize / (1024.0 * 1024.0);
61+
return -1.0;
62+
#else
4463
struct rusage ru;
4564
getrusage(RUSAGE_SELF, &ru);
4665
#if defined(__APPLE__)
4766
return ru.ru_maxrss / (1024.0 * 1024.0);
4867
#else
4968
return ru.ru_maxrss / 1024.0;
5069
#endif
70+
#endif
5171
}
5272
// Returns the available (free) physical memory in MB.
5373
static double available_mem_mb()

0 commit comments

Comments
 (0)