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:
+80
-25
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user