fix(benchmark): prevent disk exhaustion during benchmark runs

- add EXIT/INT/TERM trap to clean up /tmp artifacts on script exit or interrupt
- introduce DISK_SAFETY_MARGIN_MB constant to reserve 200MB free at all times
- build disk test configurations dynamically based on available space instead of a fixed list
- re-check free space before each test pass and skip configs that no longer fit
- return early with SCORE_DISK_WRITE=0 when no test fits in available space
This commit is contained in:
2026-05-12 22:43:14 -04:00
parent 15c42e1f24
commit 2a50724328
+80 -25
View File
@@ -12,6 +12,25 @@ eval "$_lib"
unset _lib
export LXS_LOG_FILE="/tmp/lxs_benchmark.log"
# Always clean up benchmark artifacts on exit, even on error or Ctrl+C. Without
# this, a partial 1-2GB dd file in /tmp can stay behind and fill the disk on
# small servers if the script is re-run.
cleanup_benchmark_artifacts() {
rm -f /tmp/lxs_test_write_* \
/tmp/lxs_test_read_* \
/tmp/lxs_write_result_*.tmp \
/tmp/lxs_read_result_*.tmp \
/tmp/lxs_cpu_result.tmp \
/tmp/lxs_ram_result.tmp \
/tmp/lxs_ping_result.tmp \
/tmp/lxs_ping_*.tmp 2>/dev/null || true
}
trap cleanup_benchmark_artifacts EXIT INT TERM
# Minimum free space (MB) to keep available during disk tests. If /tmp drops
# below this threshold mid-run we abort the remaining passes.
DISK_SAFETY_MARGIN_MB=200
# ═══════════════════════════════════════════════════════════════════════════
# Score Variables
# ═══════════════════════════════════════════════════════════════════════════
@@ -176,20 +195,30 @@ test_memory() {
test_disk_write() {
echo -e "${WHITE}${BOLD}DISK WRITE PERFORMANCE TEST${NC}"
show_separator
# Check available disk space in /tmp
local available_space=$(df -BM /tmp | awk 'NR==2 {print $4}' | sed 's/M//')
# Test configurations: size_mb, block_size, description
local test_configs=(
"100:1M:100MB Sequential"
"1024:1M:1GB Sequential"
)
# Add 2GB test only if we have enough space (at least 3GB free)
if [ "$available_space" -gt 3072 ]; then
# Build test configurations dynamically based on free space. Each test needs
# room for its file PLUS the safety margin, otherwise dd can fill the disk
# on small servers (1-2GB VPS). Tests are added from smallest to largest.
local test_configs=()
if [ "$available_space" -gt $((100 + DISK_SAFETY_MARGIN_MB)) ]; then
test_configs+=("100:1M:100MB Sequential")
fi
if [ "$available_space" -gt $((1024 + DISK_SAFETY_MARGIN_MB)) ]; then
test_configs+=("1024:1M:1GB Sequential")
fi
if [ "$available_space" -gt $((2048 + DISK_SAFETY_MARGIN_MB)) ]; then
test_configs+=("2048:1M:2GB Sequential")
fi
if [ ${#test_configs[@]} -eq 0 ]; then
echo -e "${RED}[✗] Not enough free space on /tmp (${available_space}MB) to run any write test${NC}"
SCORE_DISK_WRITE=0
echo ""
return 0
fi
local all_speeds=()
local all_speeds_mb=()
@@ -202,16 +231,24 @@ test_disk_write() {
echo -e "${YELLOW}[!] Limited disk space (${available_space}MB free), running reduced test set${NC}"
fi
echo ""
# Run tests for each configuration
for config in "${test_configs[@]}"; do
local size_mb=$(echo "$config" | cut -d':' -f1)
local block_size=$(echo "$config" | cut -d':' -f2)
local description=$(echo "$config" | cut -d':' -f3)
local pass_speeds=()
local pass_count=0
# Re-check free space before each config; the previous test may have
# left the filesystem tighter than expected (cache, logs, etc.).
local current_free=$(df -BM /tmp | awk 'NR==2 {print $4}' | sed 's/M//')
if [ "$current_free" -lt $((size_mb + DISK_SAFETY_MARGIN_MB)) ]; then
printf "\r${YELLOW}[!]${NC} ${description}: Skipped (only ${current_free}MB free)\n"
continue
fi
# Run 3 passes for each configuration
for pass in 1 2 3; do
# Clean up before test
@@ -342,20 +379,30 @@ test_disk_write() {
test_disk_read() {
echo -e "${WHITE}${BOLD}DISK READ PERFORMANCE TEST${NC}"
show_separator
# Check available disk space in /tmp
local available_space=$(df -BM /tmp | awk 'NR==2 {print $4}' | sed 's/M//')
# Test configurations: size_mb, block_size, description
local test_configs=(
"100:1M:100MB Sequential"
"1024:1M:1GB Sequential"
)
# Add 2GB test only if we have enough space (at least 3GB free)
if [ "$available_space" -gt 3072 ]; then
# Build test configurations dynamically based on free space (see write test
# for rationale). The read test also writes a source file first, so the
# space requirement is the same as the write test.
local test_configs=()
if [ "$available_space" -gt $((100 + DISK_SAFETY_MARGIN_MB)) ]; then
test_configs+=("100:1M:100MB Sequential")
fi
if [ "$available_space" -gt $((1024 + DISK_SAFETY_MARGIN_MB)) ]; then
test_configs+=("1024:1M:1GB Sequential")
fi
if [ "$available_space" -gt $((2048 + DISK_SAFETY_MARGIN_MB)) ]; then
test_configs+=("2048:1M:2GB Sequential")
fi
if [ ${#test_configs[@]} -eq 0 ]; then
echo -e "${RED}[✗] Not enough free space on /tmp (${available_space}MB) to run any read test${NC}"
SCORE_DISK_READ=0
echo ""
return 0
fi
local all_speeds_mb=()
local test_count=0
@@ -373,11 +420,19 @@ test_disk_read() {
local size_mb=$(echo "$config" | cut -d':' -f1)
local block_size=$(echo "$config" | cut -d':' -f2)
local description=$(echo "$config" | cut -d':' -f3)
# Re-check free space before each config (same rationale as write test).
local current_free=$(df -BM /tmp | awk 'NR==2 {print $4}' | sed 's/M//')
if [ "$current_free" -lt $((size_mb + DISK_SAFETY_MARGIN_MB)) ]; then
printf "\r${YELLOW}[!]${NC} ${description}: Skipped (only ${current_free}MB free)\n"
continue
fi
# Create test file if it doesn't exist
if [ ! -f /tmp/lxs_test_read_${size_mb} ]; then
dd if=/dev/zero of=/tmp/lxs_test_read_${size_mb} bs=${block_size} count=${size_mb} 2>/dev/null || {
# If file creation fails, skip this test
# If file creation fails, skip this test and remove any partial file
rm -f /tmp/lxs_test_read_${size_mb}
continue
}
sync