diff --git a/benchmark_network.sh b/benchmark_network.sh index 6905f15..e827fc0 100755 --- a/benchmark_network.sh +++ b/benchmark_network.sh @@ -8,6 +8,9 @@ # - WAN with packet loss # - WAN with jitter # +# All network-based tools (fastsync, rsync, rclone) are tested with the SAME +# network conditions applied via tc netem on the loopback interface. +# # Usage: # ./benchmark_network.sh [SCENARIO] [DATA_SIZE_MB] [RUN_COUNT] # @@ -90,7 +93,10 @@ case "$SCENARIO" in ;; esac -PORT=19399 +# ── Ports ──────────────────────────────────────────────────────────────── +FASTSYNC_PORT=19399 +RSYNC_PORT=19400 +RCLONE_PORT=19401 HOST="127.0.0.1" SERVER_BIN="./fastsync_server" @@ -100,6 +106,7 @@ CLIENT_BIN="./fastsync_client" TEST_DIR="network_bench_$$" SRC_DIR="$TEST_DIR/src" DST_DIR_BASE="$TEST_DIR/dst" +RSYNC_MODULE_DIR="$TEST_DIR/rsync_module" # ── Colours ──────────────────────────────────────────────────────────────── RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m' @@ -142,7 +149,6 @@ setup_network() { cleanup_network() { sudo tc qdisc del dev lo root 2>/dev/null || true - ok "Network simulation removed" } # ── Sanity checks ────────────────────────────────────────────────────────── @@ -152,21 +158,52 @@ 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") + +# Variable to track rsyncd PID +RSYNCD_PID="" cleanup() { cleanup_network + # Kill rsyncd if running + if [ -n "$RSYNCD_PID" ] && kill -0 "$RSYNCD_PID" 2>/dev/null; then + kill "$RSYNCD_PID" 2>/dev/null || true + wait "$RSYNCD_PID" 2>/dev/null || true + fi pkill -f "fastsync_server" 2>/dev/null || true pkill -f "fastsync_client" 2>/dev/null || true rm -rf "$TEST_DIR" } trap cleanup EXIT +# ── Start rsync daemon ──────────────────────────────────────────────────── +start_rsyncd() { + # Create rsyncd config file + local config_file="$TEST_DIR/rsyncd.conf" + cat > "$config_file" < /dev/null 2>&1 & + RSYNCD_PID=$! + sleep 0.5 + + # Verify it's running + if ! kill -0 "$RSYNCD_PID" 2>/dev/null; then + die "Failed to start rsync daemon" + fi + ok "rsync daemon started on port $RSYNC_PORT" +} + # ── Generate test data ────────────────────────────────────────────────────── generate_test_data() { info "Generating ~${DATA_SIZE_MB}MB test data..." rm -rf "$TEST_DIR" mkdir -p "$SRC_DIR/small" "$SRC_DIR/medium" "$SRC_DIR/large" + mkdir -p "$RSYNC_MODULE_DIR" # Small files: many small files to test overhead (~25% of total) local small_count=$(( (DATA_SIZE_MB * 1048576 / 4) / 262144 )) @@ -198,6 +235,10 @@ generate_test_data() { dd if=/dev/urandom bs=1M count=$this_size of="$SRC_DIR/large/file_$i.bin" 2>/dev/null done + # Also copy data to rsync module directory + info " Copying data to rsync module directory..." + cp -r "$SRC_DIR"/* "$RSYNC_MODULE_DIR/" 2>/dev/null + local total_files total_size total_files=$(find "$SRC_DIR" -type f | wc -l) total_size=$(du -sh "$SRC_DIR" | cut -f1) @@ -224,7 +265,7 @@ verify_sync() { run_fastsync() { local nconn=$1 local dst_dir="$DST_DIR_BASE/fastsync_${nconn}" - local server_port=$((PORT + nconn)) + local server_port=$((FASTSYNC_PORT + nconn)) rm -rf "$dst_dir" mkdir -p "$dst_dir" @@ -260,8 +301,8 @@ run_fastsync() { rm -rf "$dst_dir" } -# ── Run rsync test ──────────────────────────────────────────────────────── -run_rsync() { +# ── Run rsync test over TCP (through rsyncd) ────────────────────────────── +run_rsync_tcp() { local use_compress=${1:-0} local dst_dir="$DST_DIR_BASE/rsync_${use_compress}" @@ -271,10 +312,11 @@ run_rsync() { local start end start=$(date +%s%N) + # Use rsync:// protocol to go through TCP on loopback (experiences network simulation) if [ "$use_compress" -eq 1 ]; then - rsync -a --compress "$SRC_DIR/" "$dst_dir/" > /dev/null 2>&1 + rsync -a --compress "rsync://$HOST:$RSYNC_PORT/test_module/" "$dst_dir/" > /dev/null 2>&1 else - rsync -a "$SRC_DIR/" "$dst_dir/" > /dev/null 2>&1 + rsync -a "rsync://$HOST:$RSYNC_PORT/test_module/" "$dst_dir/" > /dev/null 2>&1 fi end=$(date +%s%N) @@ -299,7 +341,7 @@ run_rsync() { rm -rf "$dst_dir" } -# ── Run cp test (baseline) ──────────────────────────────────────────────── +# ── Run cp test (local baseline - no network) ────────────────────────────── run_cp() { local dst_dir="$DST_DIR_BASE/cp" @@ -330,8 +372,8 @@ run_cp() { rm -rf "$dst_dir" } -# ── Run rclone test (if available) ──────────────────────────────────────── -run_rclone() { +# ── Run rclone test over TCP (if available) ──────────────────────────────── +run_rclone_tcp() { if [ "$HAS_RCLONE" -eq 0 ]; then echo "0|0|0" return @@ -341,11 +383,20 @@ run_rclone() { rm -rf "$dst_dir" mkdir -p "$dst_dir" + # Start rclone serve in background + rclone serve http --addr "$HOST:$RCLONE_PORT" --baseurl / "$SRC_DIR" > /dev/null 2>&1 & + local rclone_pid=$! + sleep 1 + local start end start=$(date +%s%N) - rclone copy "$SRC_DIR" "$dst_dir" -q --transfers 4 --checkers 8 2>/dev/null || true + # Use HTTP which goes through TCP on loopback + rclone copy "http://$HOST:$RCLONE_PORT" "$dst_dir" -q --transfers 4 --checkers 8 2>/dev/null || true end=$(date +%s%N) + kill "$rclone_pid" 2>/dev/null || true + wait "$rclone_pid" 2>/dev/null || true + 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}') @@ -401,6 +452,15 @@ echo "" # Setup network conditions setup_network + +# Start rsync daemon (for TCP-based rsync tests) +start_rsyncd + +# Copy data to rsync module +info "Preparing rsync module..." +cp -r "$SRC_DIR"/* "$RSYNC_MODULE_DIR/" 2>/dev/null + +generate_test_data echo "" # Connection counts to test for fastSyncAI @@ -410,13 +470,12 @@ CONN_COUNTS=(1 2 4 8 16) 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 "" +# ── Phase 1: Network-based tools (all experience network simulation) ────────── +info "Testing tools over simulated network ${SCENARIO_NAME}..." -# ── Test fastSyncAI with different connection counts ─────────────────────── -info "Testing fastSyncAI with different connection counts..." +# Test fastSyncAI with different connection counts for nconn in "${CONN_COUNTS[@]}"; do - echo -n " Testing ${nconn} connections... " + echo -n " Testing fastSyncAI ${nconn} connections... " result=$(run_fastsync "$nconn") IFS='|' read -r ms mbs verified <<< "$result" FS_RESULTS+=("$ms|$mbs|$verified") @@ -427,13 +486,9 @@ 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) +# Test rsync over TCP (through rsyncd on loopback - experiences network simulation) +echo -n " Testing rsync over TCP... " +result=$(run_rsync_tcp 0) IFS='|' read -r ms mbs verified <<< "$result" RS_RESULTS=("$ms|$mbs|$verified") if [ "$verified" -eq 1 ]; then @@ -442,9 +497,9 @@ else warn "${mbs} MB/s (${ms}ms) - VERIFICATION FAILED" fi -# ── Test rsync with compression ──────────────────────────────────────────── -echo -n " Testing rsync + compress... " -result=$(run_rsync 1) +# Test rsync with compression over TCP +echo -n " Testing rsync + compress over TCP... " +result=$(run_rsync_tcp 1) IFS='|' read -r ms mbs verified <<< "$result" RSC_RESULTS=("$ms|$mbs|$verified") if [ "$verified" -eq 1 ]; then @@ -453,21 +508,10 @@ 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) ──────────────────────────────────────────── +# Test rclone over TCP (if available) if [ "$HAS_RCLONE" -eq 1 ]; then - echo -n " Testing rclone... " - result=$(run_rclone) + echo -n " Testing rclone over TCP... " + result=$(run_rclone_tcp) IFS='|' read -r ms mbs verified <<< "$result" RCLONE_RESULTS=("$ms|$mbs|$verified") if [ "$verified" -eq 1 ]; then @@ -479,10 +523,25 @@ else warn "rclone not installed - skipping" fi +# Cleanup network simulation (for local cp baseline) +cleanup_network + +# ── Phase 2: Local baseline (cp - no network) ──────────────────────────────── +echo -n " Testing cp (local 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 + echo "" echo -e "${BOLD}═══════════════════════════════════════════════════════════════════════════╗${RESET}" echo -e "${BOLD} NETWORK CONDITION RESULTS${RESET}" echo -e "${BOLD} Scenario: ${SCENARIO_NAME}${RESET}" +echo -e "${BOLD} (All TCP tools tested with network simulation)${RESET}" echo -e "${BOLD}═══════════════════════════════════════════════════════════════════════════╝${RESET}" echo "" @@ -501,49 +560,51 @@ 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" "-------------------------" "----------" "----------" "-----------" "--------" +echo " === fastSyncAI (Multi-connection, over TCP with ${SCENARIO_NAME}) ===" +printf " %-30s %-10s %-10s %s %s\n" "Configuration" "Time (ms)" "MB/s" "Throughput" "Verified" +printf " %-30s %-10s %-10s %s %s\n" "------------------------------" "----------" "----------" "-----------" "--------" for i in "${!FS_RESULTS[@]}"; do IFS='|' read -r ms mbs verified <<< "${FS_RESULTS[$i]}" bar=$(draw_bar "$mbs" "$MAX_MBS") verified_str=$([ "$verified" -eq 1 ] && echo "✓" || echo "✗") - printf " %-25s %-10s %-10s %s %s\n" "${FS_LABELS[$i]}" "$ms" "$mbs" "$bar" "$verified_str" + printf " %-30s %-10s %-10s %s %s\n" "${FS_LABELS[$i]}" "$ms" "$mbs" "$bar" "$verified_str" done -# ── Print other tool results ─────────────────────────────────────────────── +# ── Print other tool results (TCP-based, with network simulation) ──────────── 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" "--------------------" "----------" "----------" "-----------" "--------" +echo " === Other Network Tools (over TCP with ${SCENARIO_NAME}) ===" +printf " %-30s %-10s %-10s %s %s\n" "Tool" "Time (ms)" "MB/s" "Throughput" "Verified" +printf " %-30s %-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" +printf " %-30s %-10s %-10s %s %s\n" "rsync (TCP)" "$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" +printf " %-30s %-10s %-10s %s %s\n" "rsync + compress (TCP)" "$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" + printf " %-30s %-10s %-10s %s %s\n" "rclone (TCP)" "$ms" "$mbs" "$bar" "$verified_str" fi +# cp (local baseline - separate section) +echo "" +echo " === Local Baseline (no network) ===" +IFS='|' read -r ms mbs verified <<< "${CP_RESULTS[0]}" +bar=$(draw_bar "$mbs" "$MAX_MBS") +verified_str=$([ "$verified" -eq 1 ] && echo "✓" || echo "✗") +printf " %-30s %-10s %-10s %s %s\n" "cp (local baseline)" "$ms" "$mbs" "$bar" "$verified_str" + # ── Find best configuration and speedup analysis ──────────────────────────── echo "" echo -e "${BOLD}═══════════════════════════════════════════════════════════════════════════╗${RESET}" @@ -568,9 +629,9 @@ 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 +# Speedup vs rsync (both over same network conditions) echo "" -echo "Speedup vs rsync (under ${SCENARIO_NAME}):" +echo "Speedup vs rsync (both over ${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" @@ -586,5 +647,15 @@ if [ "$(awk "BEGIN {print ($rs_mbs > 0) ? 1 : 0}")" = "1" ]; then fi fi +# Compare to local cp to show network overhead +echo "" +echo "Network overhead (vs local cp):" +IFS='|' read -r cp_ms cp_mbs cp_verified <<< "${CP_RESULTS[0]}" +if [ "$(awk "BEGIN {print ($cp_mbs > 0) ? 1 : 0}")" = "1" ]; then + overhead_pct=$(awk "BEGIN {printf \"%.1f\", (1 - $best_fs_mbs / $cp_mbs) * 100}") + ratio=$(awk "BEGIN {printf \"%.2f\", $cp_mbs / ($best_fs_mbs == 0 ? 0.01 : $best_fs_mbs)}") + echo -e " cp is ${ratio}x faster than best fastSyncAI (${overhead_pct}% overhead from network simulation)" +fi + echo "" ok "Network benchmark complete!"