diff --git a/benchmark_network.sh b/benchmark_network.sh index 7ca4c7a..6905f15 100755 --- a/benchmark_network.sh +++ b/benchmark_network.sh @@ -2,7 +2,7 @@ # ============================================================================= # benchmark_network.sh — Network Condition Benchmark for fastSyncAI # -# Tests fastSyncAI performance under various realistic network conditions: +# Tests fastSyncAI and other tools under various realistic network conditions: # - LAN (low latency, high bandwidth) # - WAN (high latency, moderate bandwidth) # - WAN with packet loss @@ -99,7 +99,7 @@ CLIENT_BIN="./fastsync_client" # ── Directories ──────────────────────────────────────────────────────────── TEST_DIR="network_bench_$$" SRC_DIR="$TEST_DIR/src" -DST_DIR="$TEST_DIR/dst" +DST_DIR_BASE="$TEST_DIR/dst" # ── Colours ──────────────────────────────────────────────────────────────── RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m' @@ -148,6 +148,11 @@ cleanup_network() { # ── Sanity checks ────────────────────────────────────────────────────────── [ -x "$SERVER_BIN" ] || die "Server binary not found: $SERVER_BIN — run 'make' first." [ -x "$CLIENT_BIN" ] || die "Client binary not found: $CLIENT_BIN — run 'make' first." +command -v rsync >/dev/null 2>&1 || die "rsync not found. Install rsync first." + +# Check for optional tools +HAS_RCLONE=$(command -v rclone >/dev/null 2>&1 && echo "1" || echo "0") +HAS_UNISON=$(command -v unison >/dev/null 2>&1 && echo "1" || echo "0") cleanup() { cleanup_network @@ -215,10 +220,10 @@ verify_sync() { return 0 } -# ── Run single test with connection count ────────────────────────────────── -run_test() { +# ── Run fastSyncAI test ──────────────────────────────────────────────────── +run_fastsync() { local nconn=$1 - local dst_dir="$DST_DIR/fastsync_${nconn}" + local dst_dir="$DST_DIR_BASE/fastsync_${nconn}" local server_port=$((PORT + nconn)) rm -rf "$dst_dir" @@ -255,6 +260,109 @@ run_test() { rm -rf "$dst_dir" } +# ── Run rsync test ──────────────────────────────────────────────────────── +run_rsync() { + local use_compress=${1:-0} + local dst_dir="$DST_DIR_BASE/rsync_${use_compress}" + + rm -rf "$dst_dir" + mkdir -p "$dst_dir" + + local start end + start=$(date +%s%N) + + if [ "$use_compress" -eq 1 ]; then + rsync -a --compress "$SRC_DIR/" "$dst_dir/" > /dev/null 2>&1 + else + rsync -a "$SRC_DIR/" "$dst_dir/" > /dev/null 2>&1 + fi + + end=$(date +%s%N) + local elapsed_ms=$(( (end - start) / 1000000 )) + + # Calculate throughput + local total_bytes + total_bytes=$(find "$SRC_DIR" -type f -exec stat -c %s {} \; | awk '{sum+=$1} END {print sum}') + local mbs=0 + if [ "$elapsed_ms" -gt 0 ]; then + mbs=$(awk "BEGIN {printf \"%.2f\", $total_bytes / 1048576.0 / ($elapsed_ms / 1000.0)}") + fi + + local verified=1 + if ! verify_sync "$SRC_DIR" "$dst_dir"; then + verified=0 + fi + + echo "${elapsed_ms}|${mbs}|${verified}" + + # Cleanup + rm -rf "$dst_dir" +} + +# ── Run cp test (baseline) ──────────────────────────────────────────────── +run_cp() { + local dst_dir="$DST_DIR_BASE/cp" + + rm -rf "$dst_dir" + mkdir -p "$dst_dir" + + local start end + start=$(date +%s%N) + cp -r "$SRC_DIR"/* "$dst_dir/" 2>/dev/null + end=$(date +%s%N) + + local elapsed_ms=$(( (end - start) / 1000000 )) + + local total_bytes + total_bytes=$(find "$SRC_DIR" -type f -exec stat -c %s {} \; | awk '{sum+=$1} END {print sum}') + local mbs=0 + if [ "$elapsed_ms" -gt 0 ]; then + mbs=$(awk "BEGIN {printf \"%.2f\", $total_bytes / 1048576.0 / ($elapsed_ms / 1000.0)}") + fi + + local verified=1 + if ! verify_sync "$SRC_DIR" "$dst_dir"; then + verified=0 + fi + + echo "${elapsed_ms}|${mbs}|${verified}" + + rm -rf "$dst_dir" +} + +# ── Run rclone test (if available) ──────────────────────────────────────── +run_rclone() { + if [ "$HAS_RCLONE" -eq 0 ]; then + echo "0|0|0" + return + fi + + local dst_dir="$DST_DIR_BASE/rclone" + rm -rf "$dst_dir" + mkdir -p "$dst_dir" + + local start end + start=$(date +%s%N) + rclone copy "$SRC_DIR" "$dst_dir" -q --transfers 4 --checkers 8 2>/dev/null || true + end=$(date +%s%N) + + local elapsed_ms=$(( (end - start) / 1000000 )) + local total_bytes + total_bytes=$(find "$SRC_DIR" -type f -exec stat -c %s {} \; | awk '{sum+=$1} END {print sum}') + local mbs=0 + if [ "$elapsed_ms" -gt 0 ]; then + mbs=$(awk "BEGIN {printf \"%.2f\", $total_bytes / 1048576.0 / ($elapsed_ms / 1000.0)}") + fi + + local verified=1 + if ! verify_sync "$SRC_DIR" "$dst_dir"; then + verified=0 + fi + + echo "${elapsed_ms}|${mbs}|${verified}" + rm -rf "$dst_dir" +} + # ── Bar chart helper ──────────────────────────────────────────────────────── draw_bar() { local val=$1 @@ -295,21 +403,21 @@ echo "" setup_network echo "" -# Connection counts to test +# Connection counts to test for fastSyncAI CONN_COUNTS=(1 2 4 8 16) -# Initialize results -declare -a FS_RESULTS +# Initialize result arrays +declare -a FS_RESULTS RS_RESULTS RSC_RESULTS CP_RESULTS RCLONE_RESULTS FS_LABELS=("fastSyncAI (1 conn)" "fastSyncAI (2 conn)" "fastSyncAI (4 conn)" "fastSyncAI (8 conn)" "fastSyncAI (16 conn)") generate_test_data echo "" -# Run tests -info "Testing fastSyncAI with different connection counts under ${SCENARIO_NAME}..." +# ── Test fastSyncAI with different connection counts ─────────────────────── +info "Testing fastSyncAI with different connection counts..." for nconn in "${CONN_COUNTS[@]}"; do echo -n " Testing ${nconn} connections... " - result=$(run_test "$nconn") + result=$(run_fastsync "$nconn") IFS='|' read -r ms mbs verified <<< "$result" FS_RESULTS+=("$ms|$mbs|$verified") if [ "$verified" -eq 1 ]; then @@ -319,6 +427,58 @@ for nconn in "${CONN_COUNTS[@]}"; do fi done +# Cleanup network for local tools (rsync, cp, rclone don't use network) +cleanup_network +echo "" + +# ── Test rsync (no compression) ───────────────────────────────────────────── +echo -n " Testing rsync... " +result=$(run_rsync 0) +IFS='|' read -r ms mbs verified <<< "$result" +RS_RESULTS=("$ms|$mbs|$verified") +if [ "$verified" -eq 1 ]; then + ok "${mbs} MB/s (${ms}ms)" +else + warn "${mbs} MB/s (${ms}ms) - VERIFICATION FAILED" +fi + +# ── Test rsync with compression ──────────────────────────────────────────── +echo -n " Testing rsync + compress... " +result=$(run_rsync 1) +IFS='|' read -r ms mbs verified <<< "$result" +RSC_RESULTS=("$ms|$mbs|$verified") +if [ "$verified" -eq 1 ]; then + ok "${mbs} MB/s (${ms}ms)" +else + warn "${mbs} MB/s (${ms}ms) - VERIFICATION FAILED" +fi + +# ── Test cp (baseline) ───────────────────────────────────────────────────── +echo -n " Testing cp (baseline)... " +result=$(run_cp) +IFS='|' read -r ms mbs verified <<< "$result" +CP_RESULTS=("$ms|$mbs|$verified") +if [ "$verified" -eq 1 ]; then + ok "${mbs} MB/s (${ms}ms)" +else + warn "${mbs} MB/s (${ms}ms) - VERIFICATION FAILED" +fi + +# ── Test rclone (if available) ──────────────────────────────────────────── +if [ "$HAS_RCLONE" -eq 1 ]; then + echo -n " Testing rclone... " + result=$(run_rclone) + IFS='|' read -r ms mbs verified <<< "$result" + RCLONE_RESULTS=("$ms|$mbs|$verified") + if [ "$verified" -eq 1 ]; then + ok "${mbs} MB/s (${ms}ms)" + else + warn "${mbs} MB/s (${ms}ms) - VERIFICATION FAILED" + fi +else + warn "rclone not installed - skipping" +fi + echo "" echo -e "${BOLD}═══════════════════════════════════════════════════════════════════════════╗${RESET}" echo -e "${BOLD} NETWORK CONDITION RESULTS${RESET}" @@ -326,10 +486,10 @@ echo -e "${BOLD} Scenario: ${SCENARIO_NAME}${RESET}" echo -e "${BOLD}═══════════════════════════════════════════════════════════════════════════╝${RESET}" echo "" -# Calculate max MB/s for bar scaling +# ── Calculate max MB/s for bar scaling ──────────────────────────────────── calc_max_mbs() { local max=0 - for res in "${FS_RESULTS[@]}"; do + for res in "${FS_RESULTS[@]}" "${RS_RESULTS[@]}" "${RSC_RESULTS[@]}" "${CP_RESULTS[@]}" "${RCLONE_RESULTS[@]}"; do local mbs=$(echo "$res" | cut -d'|' -f2) local int_mbs=$(echo "$mbs" | awk '{printf "%d", $1+0}') [ "$int_mbs" -gt "$max" ] && max=$int_mbs @@ -340,6 +500,8 @@ calc_max_mbs() { MAX_MBS=$(calc_max_mbs) [ "$MAX_MBS" -eq 0 ] && MAX_MBS=100 +# ── Print fastSyncAI results ──────────────────────────────────────────────── +echo " === fastSyncAI (Multi-connection) ===" printf " %-25s %-10s %-10s %s %s\n" "Configuration" "Time (ms)" "MB/s" "Throughput" "Verified" printf " %-25s %-10s %-10s %s %s\n" "-------------------------" "----------" "----------" "-----------" "--------" @@ -350,20 +512,79 @@ for i in "${!FS_RESULTS[@]}"; do printf " %-25s %-10s %-10s %s %s\n" "${FS_LABELS[$i]}" "$ms" "$mbs" "$bar" "$verified_str" done -# Find best configuration -best_idx=0 -best_mbs=0 +# ── Print other tool results ─────────────────────────────────────────────── +echo "" +echo " === Other Tools ===" +printf " %-25s %-10s %-10s %s %s\n" "Tool" "Time (ms)" "MB/s" "Throughput" "Verified" +printf " %-25s %-10s %-10s %s %s\n" "--------------------" "----------" "----------" "-----------" "--------" + +# rsync +IFS='|' read -r ms mbs verified <<< "${RS_RESULTS[0]}" +bar=$(draw_bar "$mbs" "$MAX_MBS") +verified_str=$([ "$verified" -eq 1 ] && echo "✓" || echo "✗") +printf " %-25s %-10s %-10s %s %s\n" "rsync" "$ms" "$mbs" "$bar" "$verified_str" + +# rsync + compress +IFS='|' read -r ms mbs verified <<< "${RSC_RESULTS[0]}" +bar=$(draw_bar "$mbs" "$MAX_MBS") +verified_str=$([ "$verified" -eq 1 ] && echo "✓" || echo "✗") +printf " %-25s %-10s %-10s %s %s\n" "rsync + compress" "$ms" "$mbs" "$bar" "$verified_str" + +# cp (baseline) +IFS='|' read -r ms mbs verified <<< "${CP_RESULTS[0]}" +bar=$(draw_bar "$mbs" "$MAX_MBS") +verified_str=$([ "$verified" -eq 1 ] && echo "✓" || echo "✗") +printf " %-25s %-10s %-10s %s %s\n" "cp (baseline)" "$ms" "$mbs" "$bar" "$verified_str" + +# rclone +if [ "${RCLONE_RESULTS[0]}" != "0|0|0" ]; then + IFS='|' read -r ms mbs verified <<< "${RCLONE_RESULTS[0]}" + bar=$(draw_bar "$mbs" "$MAX_MBS") + verified_str=$([ "$verified" -eq 1 ] && echo "✓" || echo "✗") + printf " %-25s %-10s %-10s %s %s\n" "rclone" "$ms" "$mbs" "$bar" "$verified_str" +fi + +# ── Find best configuration and speedup analysis ──────────────────────────── +echo "" +echo -e "${BOLD}═══════════════════════════════════════════════════════════════════════════╗${RESET}" +echo -e "${BOLD} ANALYSIS${RESET}" +echo -e "${BOLD}═══════════════════════════════════════════════════════════════════════════╝${RESET}" +echo "" + +# Find best fastSyncAI config +best_fs_idx=0 +best_fs_mbs=0 for i in "${!FS_RESULTS[@]}"; do IFS='|' read -r ms mbs verified <<< "${FS_RESULTS[$i]}" mbs_int=$(echo "$mbs" | awk '{printf "%d", $1+0}') - if [ "$mbs_int" -gt "$best_mbs" ]; then - best_mbs=$mbs_int - best_idx=$i + if [ "$mbs_int" -gt "$best_fs_mbs" ]; then + best_fs_mbs=$mbs_int + best_fs_idx=$i fi done +# Get rsync MB/s for comparison +IFS='|' read -r rs_ms rs_mbs rs_verified <<< "${RS_RESULTS[0]}" + +ok "Best fastSyncAI config: ${FS_LABELS[$best_fs_idx]} (${best_fs_mbs} MB/s)" + +# Speedup vs rsync echo "" -echo -e "${BOLD}Best configuration for ${SCENARIO_NAME}:${RESET} ${FS_LABELS[$best_idx]} (${best_mbs} MB/s)" +echo "Speedup vs rsync (under ${SCENARIO_NAME}):" +if [ "$(awk "BEGIN {print ($rs_mbs > 0) ? 1 : 0}")" = "1" ]; then + best_fs_result="${FS_RESULTS[$best_fs_idx]}" + IFS='|' read -r fs_ms fs_mbs fs_verified <<< "$best_fs_result" + speedup=$(awk "BEGIN {printf \"%.2f\", $fs_mbs / ($rs_mbs == 0 ? 0.01 : $rs_mbs)}") + + if [ "$(awk "BEGIN {print ($fs_mbs > $rs_mbs) ? 1 : 0}")" = "1" ]; then + echo -e " ${GREEN}fastSyncAI (best) is ${speedup}x faster than rsync${RESET}" + elif [ "$(awk "BEGIN {print ($rs_mbs > $fs_mbs) ? 1 : 0}")" = "1" ]; then + speedup_inv=$(awk "BEGIN {printf \"%.2f\", $rs_mbs / ($fs_mbs == 0 ? 0.01 : $fs_mbs)}") + echo -e " ${GREEN}rsync is ${speedup_inv}x faster than fastSyncAI (best)${RESET}" + else + echo -e " Both performed similarly" + fi +fi echo "" ok "Network benchmark complete!"