#!/usr/bin/env bash set -euo pipefail usage() { cat <<'EOF' Usage: ./scripts/compare/run_perf_compare_quick_remote.sh \ --run-root \ --remote-root \ [--rir-set ] \ [--ssh-target ] \ [--rpki-client-bin ] \ [--libtls-path ] \ [--rp-run-mode ] \ [--copy-rpki-client-cache] \ [--probe-rpki-client-cache] \ [--ours-extra-args ''] \ [--dry-run] EOF } ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" first_existing_executable() { local fallback="$1" shift local candidate for candidate in "$@"; do if [[ -x "$candidate" ]]; then printf '%s' "$candidate" return fi done printf '%s' "$fallback" } first_existing_file() { local fallback="$1" shift local candidate for candidate in "$@"; do if [[ -f "$candidate" ]]; then printf '%s' "$candidate" return fi done printf '%s' "$fallback" } RUN_ROOT="" REMOTE_ROOT="" SSH_TARGET="${SSH_TARGET:-root@47.251.56.108}" RPKI_CLIENT_BIN="${RPKI_CLIENT_BIN:-$(first_existing_executable \ "/home/yuyr/dev/rpki-client-9.7/build-m5/src/rpki-client" \ "$ROOT_DIR/../../.cache/rpki-client-9.7-build/bin/rpki-client" \ "$ROOT_DIR/../../.cache/rpki-client-9.7-build/src/rpki-client-9.7/src/rpki-client" \ "$ROOT_DIR/../../.cache/rpki-client-remote9.0/rpki-client" \ "/home/yuyr/dev/rpki-client-9.7/build-m5/src/rpki-client")}" LIBTLS_PATH="${LIBTLS_PATH:-$(first_existing_file \ "/home/yuyr/dev/rpki-client-9.7/.deps/libtls/root/usr/lib/x86_64-linux-gnu/libtls.so.28.0.0" \ "$ROOT_DIR/../../.cache/rpki-client-9.7-build/runlib/libtls.so.28" \ "$ROOT_DIR/../../.cache/rpki-client-9.7-build/sysroot/usr/lib/x86_64-linux-gnu/libtls.so.28.0.0" \ "$ROOT_DIR/../../.cache/rpki-client-remote9.0/libtls.so.28" \ "/home/yuyr/dev/rpki-client-9.7/.deps/libtls/root/usr/lib/x86_64-linux-gnu/libtls.so.28.0.0")}" RP_RUN_MODE="${RP_RUN_MODE:-serial}" RIR_SET="${RIR_SET:-mixed2}" OURS_EXTRA_ARGS="${OURS_EXTRA_ARGS:-}" COPY_RPKI_CLIENT_CACHE="${COPY_RPKI_CLIENT_CACHE:-0}" PROBE_RPKI_CLIENT_CACHE="${PROBE_RPKI_CLIENT_CACHE:-0}" DRY_RUN=0 while [[ $# -gt 0 ]]; do case "$1" in --run-root) RUN_ROOT="$2"; shift 2 ;; --remote-root) REMOTE_ROOT="$2"; shift 2 ;; --rir-set) RIR_SET="$2"; shift 2 ;; --ssh-target) SSH_TARGET="$2"; shift 2 ;; --rpki-client-bin) RPKI_CLIENT_BIN="$2"; shift 2 ;; --libtls-path) LIBTLS_PATH="$2"; shift 2 ;; --rp-run-mode) RP_RUN_MODE="$2"; shift 2 ;; --copy-rpki-client-cache) COPY_RPKI_CLIENT_CACHE=1; shift ;; --probe-rpki-client-cache) PROBE_RPKI_CLIENT_CACHE=1; shift ;; --ours-extra-args) OURS_EXTRA_ARGS="$2"; shift 2 ;; --dry-run) DRY_RUN=1; shift ;; -h|--help) usage; exit 0 ;; *) echo "unknown argument: $1" >&2; usage; exit 2 ;; esac done [[ -n "$RUN_ROOT" && -n "$REMOTE_ROOT" ]] || { usage >&2; exit 2; } [[ "$RP_RUN_MODE" == "serial" || "$RP_RUN_MODE" == "parallel" ]] || { echo "invalid --rp-run-mode: $RP_RUN_MODE" >&2; usage; exit 2; } [[ "$RIR_SET" == "mixed2" || "$RIR_SET" == "all5" ]] || { echo "invalid --rir-set: $RIR_SET" >&2; usage; exit 2; } [[ "$DRY_RUN" -eq 1 || -x "$RPKI_CLIENT_BIN" ]] || { echo "rpki-client binary not executable: $RPKI_CLIENT_BIN" >&2; exit 2; } [[ "$DRY_RUN" -eq 1 || -f "$LIBTLS_PATH" ]] || { echo "libtls not found: $LIBTLS_PATH" >&2; exit 2; } RUN_ROOT="$(python3 - <<'PY' "$RUN_ROOT" from pathlib import Path import sys print(Path(sys.argv[1]).resolve()) PY )" mkdir -p "$RUN_ROOT/steps/step-001/ours" "$RUN_ROOT/steps/step-001/rpki-client" "$RUN_ROOT/steps/step-001/compare" mkdir -p "$RUN_ROOT/steps/step-002/ours" "$RUN_ROOT/steps/step-002/rpki-client" "$RUN_ROOT/steps/step-002/compare" tal_path_for_rir() { case "$1" in afrinic) printf '%s' "$ROOT_DIR/tests/fixtures/tal/afrinic.tal" ;; apnic) printf '%s' "$ROOT_DIR/tests/fixtures/tal/apnic-rfc7730-https.tal" ;; arin) printf '%s' "$ROOT_DIR/tests/fixtures/tal/arin.tal" ;; lacnic) printf '%s' "$ROOT_DIR/tests/fixtures/tal/lacnic.tal" ;; ripe) printf '%s' "$ROOT_DIR/tests/fixtures/tal/ripe-ncc.tal" ;; *) echo "unknown rir: $1" >&2; exit 2 ;; esac } ta_path_for_rir() { case "$1" in afrinic) printf '%s' "$ROOT_DIR/tests/fixtures/ta/afrinic-ta.cer" ;; apnic) printf '%s' "$ROOT_DIR/tests/fixtures/ta/apnic-ta.cer" ;; arin) printf '%s' "$ROOT_DIR/tests/fixtures/ta/arin-ta.cer" ;; lacnic) printf '%s' "$ROOT_DIR/tests/fixtures/ta/lacnic-ta.cer" ;; ripe) printf '%s' "$ROOT_DIR/tests/fixtures/ta/ripe-ncc-ta.cer" ;; *) echo "unknown rir: $1" >&2; exit 2 ;; esac } case "$RIR_SET" in mixed2) RIRS=(apnic arin) SCOPE_LABEL="APNIC+ARIN mixed release two-step synchronized compare" ;; all5) RIRS=(afrinic apnic arin lacnic ripe) SCOPE_LABEL="all-five-RIR mixed release two-step synchronized compare" ;; esac COPY_FILES=() for rir in "${RIRS[@]}"; do COPY_FILES+=("$(tal_path_for_rir "$rir")" "$(ta_path_for_rir "$rir")") done if [[ "$DRY_RUN" -eq 1 ]]; then cat </dev/null 2>&1 || true fi } trap cleanup_remote EXIT ( cd "$ROOT_DIR" cargo build --release --bin rpki --bin ccr_to_compare_views --bin ccr_state_compare --bin cir_state_compare --bin cir_probe_rpki_client_cache ) ssh "$SSH_TARGET" "set -e; systemctl disable --now rpki-client.timer >/dev/null 2>&1 || true; systemctl stop rpki-client.service >/dev/null 2>&1 || true; pkill -f '[/]rpki-client([[:space:]]|$)' >/dev/null 2>&1 || true; pkill -f '[/]routinator([[:space:]]|$)' >/dev/null 2>&1 || true; id -u _rpki-client >/dev/null 2>&1 || useradd -r -M -s /usr/sbin/nologin _rpki-client || true; rm -rf '$REMOTE_ROOT'; mkdir -p '$REMOTE_ROOT/bin' '$REMOTE_ROOT/lib' '$REMOTE_ROOT/state/ours' '$REMOTE_ROOT/state/rpki-client' '$REMOTE_ROOT/steps/step-001/ours' '$REMOTE_ROOT/steps/step-001/rpki-client' '$REMOTE_ROOT/steps/step-002/ours' '$REMOTE_ROOT/steps/step-002/rpki-client'" scp "$ROOT_DIR/target/release/rpki" "${COPY_FILES[@]}" "$SSH_TARGET:$REMOTE_ROOT/" if [[ "$PROBE_RPKI_CLIENT_CACHE" == "1" ]]; then scp "$ROOT_DIR/target/release/cir_probe_rpki_client_cache" "$SSH_TARGET:$REMOTE_ROOT/bin/" fi scp "$RPKI_CLIENT_BIN" "$SSH_TARGET:$REMOTE_ROOT/bin/rpki-client" scp "$LIBTLS_PATH" "$SSH_TARGET:$REMOTE_ROOT/lib/libtls.so.28" printf '%s' "$OURS_EXTRA_ARGS" | ssh "$SSH_TARGET" "cat > '$REMOTE_ROOT/ours-extra-args.txt'" printf '%s' "$RP_RUN_MODE" | ssh "$SSH_TARGET" "cat > '$REMOTE_ROOT/rp-run-mode.txt'" printf '%s' "$RIR_SET" | ssh "$SSH_TARGET" "cat > '$REMOTE_ROOT/rir-set.txt'" run_step() { local step_id="$1" local kind="$2" local local_step="$RUN_ROOT/steps/$step_id" ssh "$SSH_TARGET" bash -s -- "$REMOTE_ROOT" "$step_id" "$kind" <<'EOS' set -euo pipefail REMOTE_ROOT="$1" STEP_ID="$2" KIND="$3" cd "$REMOTE_ROOT" mkdir -p "steps/$STEP_ID/ours" "steps/$STEP_ID/rpki-client" touch rpki-client-skiplist chmod 0644 rpki-client-skiplist OURS_EXTRA_ARGS="$(cat ours-extra-args.txt)" RP_RUN_MODE="$(cat rp-run-mode.txt)" RIR_SET="$(cat rir-set.txt)" OURS_EXTRA_ARGV=() if [[ -n "$OURS_EXTRA_ARGS" ]]; then # shellcheck disable=SC2206 OURS_EXTRA_ARGV=($OURS_EXTRA_ARGS) fi case "$RIR_SET" in mixed2) RIRS=(apnic arin) ;; all5) RIRS=(afrinic apnic arin lacnic ripe) ;; *) echo "invalid rir set: $RIR_SET" >&2; exit 2 ;; esac tal_file_for_rir() { case "$1" in afrinic) printf '%s' "afrinic.tal" ;; apnic) printf '%s' "apnic-rfc7730-https.tal" ;; arin) printf '%s' "arin.tal" ;; lacnic) printf '%s' "lacnic.tal" ;; ripe) printf '%s' "ripe-ncc.tal" ;; *) echo "unknown rir: $1" >&2; exit 2 ;; esac } tal_uri_for_rir() { case "$1" in afrinic) printf '%s' "https://rpki.afrinic.net/repository/AfriNIC.cer" ;; apnic) printf '%s' "https://rpki.apnic.net/repository/apnic-rpki-root-iana-origin.cer" ;; arin) printf '%s' "https://rrdp.arin.net/arin-rpki-ta.cer" ;; lacnic) printf '%s' "https://rrdp.lacnic.net/ta/rta-lacnic-rpki.cer" ;; ripe) printf '%s' "https://rpki.ripe.net/ta/ripe-ncc-ta.cer" ;; *) echo "unknown rir: $1" >&2; exit 2 ;; esac } ta_file_for_rir() { case "$1" in afrinic) printf '%s' "afrinic-ta.cer" ;; apnic) printf '%s' "apnic-ta.cer" ;; arin) printf '%s' "arin-ta.cer" ;; lacnic) printf '%s' "lacnic-ta.cer" ;; ripe) printf '%s' "ripe-ncc-ta.cer" ;; *) echo "unknown rir: $1" >&2; exit 2 ;; esac } refresh_ta_file_for_rir() { local rir="$1" local uri local file uri="$(tal_uri_for_rir "$rir")" file="$(ta_file_for_rir "$rir")" python3 - <<'PY' "$uri" "$file" import sys import urllib.request uri, path = sys.argv[1:] request = urllib.request.Request(uri, headers={"User-Agent": "rpki-dev/compare-fast-path"}) with urllib.request.urlopen(request, timeout=30) as response: data = response.read() if not data: raise SystemExit(f"empty TA certificate response: {uri}") with open(path, "wb") as output: output.write(data) PY } for rir in "${RIRS[@]}"; do refresh_ta_file_for_rir "$rir" done OURS_TAL_ARGS=() CLIENT_TAL_ARGS=() OURS_CIR_TAL_ARGS=() for rir in "${RIRS[@]}"; do tal_file="$(tal_file_for_rir "$rir")" ta_file="$(ta_file_for_rir "$rir")" tal_uri="$(tal_uri_for_rir "$rir")" OURS_TAL_ARGS+=(--tal-path "$tal_file" --ta-path "$ta_file") OURS_CIR_TAL_ARGS+=(--cir-tal-uri "$tal_uri") CLIENT_TAL_ARGS+=(-t "../../$tal_file") done if [[ "$KIND" == "snapshot" ]]; then rm -rf state/ours/work-db state/ours/raw-store.db state/ours/repo-bytes.db state/rpki-client/cache state/rpki-client/out state/rpki-client/ta state/rpki-client/.ta fi mkdir -p state/ours/work-db state/ours/raw-store.db state/ours/repo-bytes.db state/rpki-client/cache state/rpki-client/out state/rpki-client/ta state/rpki-client/.ta chmod 0777 state/ours/work-db state/ours/raw-store.db state/ours/repo-bytes.db chmod -R 0777 state/rpki-client touch state/rpki-client/rpki-client-skiplist chmod 0644 state/rpki-client/rpki-client-skiplist START_EPOCH="$(python3 - <<'PY' import time print(time.time() + 3.0) PY )" run_ours() { python3 - <<'PY' "$START_EPOCH" import sys, time x = float(sys.argv[1]) d = x - time.time() if d > 0: time.sleep(d) PY started_ms="$(python3 - <<'PY' import time print(int(time.time() * 1000)) PY )" set +e env RPKI_PROGRESS_LOG=1 RPKI_PROGRESS_SLOW_SECS=0 ./rpki \ --db state/ours/work-db \ --raw-store-db state/ours/raw-store.db \ --repo-bytes-db state/ours/repo-bytes.db \ "${OURS_TAL_ARGS[@]}" \ "${OURS_EXTRA_ARGV[@]}" \ --ccr-out "steps/$STEP_ID/ours/result.ccr" \ --cir-enable \ --cir-out "steps/$STEP_ID/ours/result.cir" \ "${OURS_CIR_TAL_ARGS[@]}" \ --report-json "steps/$STEP_ID/ours/report.json" \ > "steps/$STEP_ID/ours/run.log" 2>&1 exit_code=$? set -e finished_ms="$(python3 - <<'PY' import time print(int(time.time() * 1000)) PY )" python3 - <<'PY' "steps/$STEP_ID/ours/round-result.json" "$STEP_ID" "$KIND" "$started_ms" "$finished_ms" "$exit_code" import json, sys path, step_id, kind, started_ms, finished_ms, exit_code = sys.argv[1:] json.dump( { "stepId": step_id, "kind": kind, "durationMs": int(finished_ms) - int(started_ms), "exitCode": int(exit_code), }, open(path, "w"), indent=2, ) PY } run_client() { cd state/rpki-client python3 - <<'PY' "$START_EPOCH" import sys, time x = float(sys.argv[1]) d = x - time.time() if d > 0: time.sleep(d) PY started_ms="$(python3 - <<'PY' import time print(int(time.time() * 1000)) PY )" set +e LD_LIBRARY_PATH="$REMOTE_ROOT/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" "$REMOTE_ROOT/bin/rpki-client" \ -vv \ -S rpki-client-skiplist \ "${CLIENT_TAL_ARGS[@]}" \ -d cache out \ > "$REMOTE_ROOT/steps/$STEP_ID/rpki-client/run.log" 2>&1 exit_code=$? set -e cp out/rpki.ccr "$REMOTE_ROOT/steps/$STEP_ID/rpki-client/result.ccr" 2>/dev/null || true cp out/rpki.cir "$REMOTE_ROOT/steps/$STEP_ID/rpki-client/result.cir" 2>/dev/null || true cp out/openbgpd "$REMOTE_ROOT/steps/$STEP_ID/rpki-client/openbgpd" 2>/dev/null || true finished_ms="$(python3 - <<'PY' import time print(int(time.time() * 1000)) PY )" python3 - <<'PY' "$REMOTE_ROOT/steps/$STEP_ID/rpki-client/round-result.json" "$STEP_ID" "$KIND" "$started_ms" "$finished_ms" "$exit_code" import json, sys path, step_id, kind, started_ms, finished_ms, exit_code = sys.argv[1:] json.dump( { "stepId": step_id, "kind": kind, "durationMs": int(finished_ms) - int(started_ms), "exitCode": int(exit_code), }, open(path, "w"), indent=2, ) PY } if [[ "$RP_RUN_MODE" == "parallel" ]]; then run_ours & OURS_PID=$! run_client & CLIENT_PID=$! wait "$OURS_PID" wait "$CLIENT_PID" else run_ours run_client fi EOS for rel in result.ccr result.cir round-result.json run.log stage-timing.json; do scp -C "$SSH_TARGET:$REMOTE_ROOT/steps/$step_id/ours/$rel" "$local_step/ours/" done for rel in result.ccr result.cir round-result.json run.log openbgpd; do scp -C "$SSH_TARGET:$REMOTE_ROOT/steps/$step_id/rpki-client/$rel" "$local_step/rpki-client/" || true done if [[ "$COPY_RPKI_CLIENT_CACHE" == "1" ]]; then mkdir -p "$local_step/rpki-client/cache" rsync -a --delete "$SSH_TARGET:$REMOTE_ROOT/state/rpki-client/cache/" "$local_step/rpki-client/cache/" fi if [[ -f "$local_step/ours/result.cir" && -f "$local_step/rpki-client/result.cir" ]]; then "$ROOT_DIR/scripts/periodic/compare_ccr_cir_round.sh" \ --ours-ccr "$local_step/ours/result.ccr" \ --rpki-client-ccr "$local_step/rpki-client/result.ccr" \ --ours-cir "$local_step/ours/result.cir" \ --rpki-client-cir "$local_step/rpki-client/result.cir" \ --out-dir "$local_step/compare" \ --trust-anchor unknown >/dev/null if [[ "$PROBE_RPKI_CLIENT_CACHE" == "1" ]]; then ssh "$SSH_TARGET" "set -e; mkdir -p '$REMOTE_ROOT/steps/$step_id/compare/cir'; '$REMOTE_ROOT/bin/cir_probe_rpki_client_cache' --ours-cir '$REMOTE_ROOT/steps/$step_id/ours/result.cir' --rpki-client-cir '$REMOTE_ROOT/steps/$step_id/rpki-client/result.cir' --cache-root '$REMOTE_ROOT/state/rpki-client/cache' --rpki-client-log '$REMOTE_ROOT/steps/$step_id/rpki-client/run.log' --out-json '$REMOTE_ROOT/steps/$step_id/compare/cir/rpki-client-cache-probe.json' --sample-limit 50 >/dev/null" scp -C "$SSH_TARGET:$REMOTE_ROOT/steps/$step_id/compare/cir/rpki-client-cache-probe.json" "$local_step/compare/cir/" fi if [[ "$COPY_RPKI_CLIENT_CACHE" == "1" ]]; then "$ROOT_DIR/target/release/cir_probe_rpki_client_cache" \ --ours-cir "$local_step/ours/result.cir" \ --rpki-client-cir "$local_step/rpki-client/result.cir" \ --cache-root "$local_step/rpki-client/cache" \ --rpki-client-log "$local_step/rpki-client/run.log" \ --out-json "$local_step/compare/cir/rpki-client-cache-probe.json" \ --sample-limit 50 >/dev/null fi else "$ROOT_DIR/scripts/periodic/compare_ccr_round.sh" \ --ours-ccr "$local_step/ours/result.ccr" \ --rpki-client-ccr "$local_step/rpki-client/result.ccr" \ --out-dir "$local_step/compare" \ --trust-anchor unknown >/dev/null fi python3 - <<'PY' "$local_step/ours/round-result.json" "$local_step/rpki-client/round-result.json" "$local_step/ours/stage-timing.json" "$local_step/compare/summary.json" "$local_step/compare/compare-summary.json" "$local_step/step-summary.json" "$OURS_EXTRA_ARGS" import json, sys ours = json.load(open(sys.argv[1])) client = json.load(open(sys.argv[2])) stage = json.load(open(sys.argv[3])) compare_path = sys.argv[4] if __import__('pathlib').Path(sys.argv[4]).exists() else sys.argv[5] compare = json.load(open(compare_path)) ours_extra_args = sys.argv[7] json.dump( { "stepId": ours["stepId"], "kind": ours["kind"], "oursExtraArgs": ours_extra_args, "oursDurationMs": ours["durationMs"], "rpkiClientDurationMs": client["durationMs"], "oursExitCode": ours["exitCode"], "rpkiClientExitCode": client["exitCode"], "oursTotalMs": stage["total_ms"], "oursRepoSyncMsTotal": stage["repo_sync_ms_total"], "oursPublicationPointRepoSyncMsTotal": stage.get("publication_point_repo_sync_ms_total"), "oursDownloadEventCount": stage.get("download_event_count"), "oursRrdpDownloadMsTotal": stage.get("rrdp_download_ms_total"), "oursRsyncDownloadMsTotal": stage.get("rsync_download_ms_total"), "oursDownloadBytesTotal": stage.get("download_bytes_total"), "oursVrps": compare["vrps"]["ours"], "rpkiClientVrps": compare["vrps"]["rpkiClient"], "oursVaps": compare["vaps"]["ours"], "rpkiClientVaps": compare["vaps"]["rpkiClient"], "vrpMatch": compare["vrps"]["match"], "vapMatch": compare["vaps"]["match"], "allMatch": compare["allMatch"], "onlyInOurs": len(compare["vrps"]["onlyInOurs"]), "onlyInRpkiClient": len(compare["vrps"]["onlyInRpkiClient"]), }, open(sys.argv[6], "w"), indent=2, ) PY } run_step step-001 snapshot run_step step-002 delta python3 - <<'PY' "$RUN_ROOT/steps/step-001/step-summary.json" "$RUN_ROOT/steps/step-002/step-summary.json" "$RUN_ROOT/summary.json" "$RP_RUN_MODE" "$OURS_EXTRA_ARGS" "$RIR_SET" "$SCOPE_LABEL" "${RIRS[@]}" import json, sys steps = [json.load(open(p)) for p in sys.argv[1:3]] summary = { "workflowName": "性能对比测试快速版", "scope": sys.argv[7], "rpRunMode": sys.argv[4], "oursExtraArgs": sys.argv[5], "rirSet": sys.argv[6], "rirs": sys.argv[8:], "steps": steps, } json.dump(summary, open(sys.argv[3], "w"), indent=2, ensure_ascii=False) print(json.dumps(summary, indent=2, ensure_ascii=False)) PY