From 2a50724328ac07580d4733624112800236f9fba5 Mon Sep 17 00:00:00 2001 From: Hyko Date: Tue, 12 May 2026 22:43:14 -0400 Subject: [PATCH] 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 --- tools/server-benchmark.sh | 105 +++++++++++++++++++++++++++++--------- 1 file changed, 80 insertions(+), 25 deletions(-) diff --git a/tools/server-benchmark.sh b/tools/server-benchmark.sh index 4932faf..6c76e26 100755 --- a/tools/server-benchmark.sh +++ b/tools/server-benchmark.sh @@ -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