|
| 1 | +#!/usr/bin/env bash |
| 2 | +set -euo pipefail |
| 3 | + |
| 4 | +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" |
| 5 | +repo_root="$(cd "$script_dir/../../.." && pwd)" |
| 6 | + |
| 7 | +run_file="$repo_root/bench/moqxprobe/.run/current" |
| 8 | +run_id="${RUN_ID:-}" |
| 9 | +rates="${DATAGRAM_RATES:-30000,32000}" |
| 10 | +probed_port="${PROBED_PORT:-9157}" |
| 11 | +quic_port="${QUICPROBE_PORT:-55433}" |
| 12 | +iperf3_port="${IPERF3_PORT:-55201}" |
| 13 | +bracket_id="${PROBED_BRACKET_ID:-}" |
| 14 | +suite_bin="${PROBED_BRACKET_SUITE_BIN:-$script_dir/remote_curl_suite.sh}" |
| 15 | + |
| 16 | +datagram_size="${DATAGRAM_SIZE:-1180}" |
| 17 | +duration_seconds="${DURATION_SECONDS:-3}" |
| 18 | +delivery_threshold="${DELIVERY_THRESHOLD:-0.95}" |
| 19 | +offered_rate_tolerance="${OFFERED_RATE_TOLERANCE:-0.95}" |
| 20 | +process_timeout_ms="${PROCESS_TIMEOUT_MS:-120000}" |
| 21 | +datagram_diagnostics="${DATAGRAM_DIAGNOSTICS:-summary}" |
| 22 | +datagram_drain_limit="${DATAGRAM_DRAIN_LIMIT:-0}" |
| 23 | + |
| 24 | +stream_count="${STREAM_COUNT:-1}" |
| 25 | +payload_size="${PAYLOAD_SIZE:-256}" |
| 26 | +payload_count="${PAYLOAD_COUNT:-2}" |
| 27 | +iperf3_tcp_duration_default="${IPERF3_TCP_DURATION:-1}" |
| 28 | +iperf3_udp_duration_default="${IPERF3_UDP_DURATION:-1}" |
| 29 | +iperf3_udp_bitrates_default="${IPERF3_UDP_BITRATES:-1M}" |
| 30 | +iperf3_udp_length_default="${IPERF3_UDP_LENGTH:-}" |
| 31 | + |
| 32 | +usage() { |
| 33 | + cat <<EOF |
| 34 | +Usage: |
| 35 | + remote_datagram_bracket.sh [options] |
| 36 | +
|
| 37 | +Options: |
| 38 | + --run-id ID Terraform/provisioning run id. Defaults to bench/moqxprobe/.run/current. |
| 39 | + --rates LIST Comma-separated DATAGRAM rates. Default: 30000,32000. |
| 40 | + --bracket-id ID Bracket id. Defaults to <run-id>-dgram-bracket-<HHMMSS>. |
| 41 | + --probed-port PORT probed HTTP port. Default: 9157. |
| 42 | + --quic-port PORT quicprobe UDP port. Default: 55433. |
| 43 | + --iperf3-port PORT iperf3 TCP/UDP port. Default: 55201. |
| 44 | + -h, --help Show this help. |
| 45 | +
|
| 46 | +Environment overrides forwarded to remote_curl_suite.sh: |
| 47 | + DATAGRAM_SIZE DATAGRAM_DIAGNOSTICS DATAGRAM_DRAIN_LIMIT |
| 48 | + DURATION_SECONDS DELIVERY_THRESHOLD OFFERED_RATE_TOLERANCE PROCESS_TIMEOUT_MS |
| 49 | + STREAM_COUNT PAYLOAD_SIZE PAYLOAD_COUNT |
| 50 | + IPERF3_TCP_DURATION IPERF3_UDP_DURATION IPERF3_UDP_BITRATES IPERF3_UDP_LENGTH |
| 51 | +
|
| 52 | +The bracket runs one baseline/stream-smoke suite, then one |
| 53 | +reference_datagram+moqx_datagram suite per requested rate. It writes an |
| 54 | +aggregate manifest under: |
| 55 | +
|
| 56 | + bench/moqxprobe/results/<run-id>/probed-datagram-bracket/<bracket-id>/manifest.json |
| 57 | +EOF |
| 58 | +} |
| 59 | + |
| 60 | +while [ "$#" -gt 0 ]; do |
| 61 | + case "$1" in |
| 62 | + --run-id) |
| 63 | + run_id="$2" |
| 64 | + shift 2 |
| 65 | + ;; |
| 66 | + --rates) |
| 67 | + rates="$2" |
| 68 | + shift 2 |
| 69 | + ;; |
| 70 | + --bracket-id) |
| 71 | + bracket_id="$2" |
| 72 | + shift 2 |
| 73 | + ;; |
| 74 | + --probed-port) |
| 75 | + probed_port="$2" |
| 76 | + shift 2 |
| 77 | + ;; |
| 78 | + --quic-port) |
| 79 | + quic_port="$2" |
| 80 | + shift 2 |
| 81 | + ;; |
| 82 | + --iperf3-port) |
| 83 | + iperf3_port="$2" |
| 84 | + shift 2 |
| 85 | + ;; |
| 86 | + -h|--help) |
| 87 | + usage |
| 88 | + exit 0 |
| 89 | + ;; |
| 90 | + *) |
| 91 | + printf 'Unknown option: %s\n' "$1" >&2 |
| 92 | + usage >&2 |
| 93 | + exit 2 |
| 94 | + ;; |
| 95 | + esac |
| 96 | +done |
| 97 | + |
| 98 | +if [ -z "$run_id" ] && [ -s "$run_file" ]; then |
| 99 | + run_id="$(cat "$run_file")" |
| 100 | +fi |
| 101 | + |
| 102 | +if [ -z "$run_id" ]; then |
| 103 | + printf '%s\n' 'Missing run id. Use --run-id or run just bench-transport-new-run first.' >&2 |
| 104 | + exit 2 |
| 105 | +fi |
| 106 | + |
| 107 | +if [ -z "$rates" ]; then |
| 108 | + printf '%s\n' 'Missing DATAGRAM rates. Use --rates or DATAGRAM_RATES.' >&2 |
| 109 | + exit 2 |
| 110 | +fi |
| 111 | + |
| 112 | +if [ -z "$bracket_id" ]; then |
| 113 | + bracket_id="${run_id}-dgram-bracket-$(date -u +%H%M%S)" |
| 114 | +fi |
| 115 | + |
| 116 | +require_tool() { |
| 117 | + if ! command -v "$1" >/dev/null 2>&1; then |
| 118 | + printf 'Missing required tool: %s\n' "$1" >&2 |
| 119 | + exit 2 |
| 120 | + fi |
| 121 | +} |
| 122 | + |
| 123 | +require_tool jq |
| 124 | +require_tool date |
| 125 | + |
| 126 | +test -x "$suite_bin" || { |
| 127 | + printf 'Suite driver is not executable: %s\n' "$suite_bin" >&2 |
| 128 | + exit 2 |
| 129 | +} |
| 130 | + |
| 131 | +IFS=',' read -r -a selected_rates <<< "$rates" |
| 132 | +for rate in "${selected_rates[@]}"; do |
| 133 | + if [ -z "$rate" ]; then |
| 134 | + printf '%s\n' 'Empty DATAGRAM rate in --rates.' >&2 |
| 135 | + exit 2 |
| 136 | + fi |
| 137 | + |
| 138 | + case "$rate" in |
| 139 | + *[!0-9]*) |
| 140 | + printf 'DATAGRAM rate must be an integer: %s\n' "$rate" >&2 |
| 141 | + exit 2 |
| 142 | + ;; |
| 143 | + esac |
| 144 | +done |
| 145 | + |
| 146 | +bench_dir="$repo_root/bench/moqxprobe" |
| 147 | +result_dir="$bench_dir/results/$run_id/probed-datagram-bracket/$bracket_id" |
| 148 | +manifest_path="$result_dir/manifest.json" |
| 149 | +invocations_file="$result_dir/invocations.jsonl" |
| 150 | +mkdir -p "$result_dir" |
| 151 | +: > "$invocations_file" |
| 152 | + |
| 153 | +timestamp="$(date -u +%Y-%m-%dT%H:%M:%SZ)" |
| 154 | +rates_json="$(printf '%s' "$rates" | jq -R 'split(",") | map(select(length > 0))')" |
| 155 | + |
| 156 | +jq -n \ |
| 157 | + --arg status "running" \ |
| 158 | + --arg run_id "$run_id" \ |
| 159 | + --arg bracket_id "$bracket_id" \ |
| 160 | + --arg started_at "$timestamp" \ |
| 161 | + --arg suite_bin "$suite_bin" \ |
| 162 | + --arg probed_port "$probed_port" \ |
| 163 | + --arg quic_port "$quic_port" \ |
| 164 | + --arg iperf3_port "$iperf3_port" \ |
| 165 | + --arg datagram_size "$datagram_size" \ |
| 166 | + --arg duration_seconds "$duration_seconds" \ |
| 167 | + --arg delivery_threshold "$delivery_threshold" \ |
| 168 | + --arg offered_rate_tolerance "$offered_rate_tolerance" \ |
| 169 | + --arg process_timeout_ms "$process_timeout_ms" \ |
| 170 | + --arg datagram_diagnostics "$datagram_diagnostics" \ |
| 171 | + --arg datagram_drain_limit "$datagram_drain_limit" \ |
| 172 | + --arg stream_count "$stream_count" \ |
| 173 | + --arg payload_size "$payload_size" \ |
| 174 | + --arg payload_count "$payload_count" \ |
| 175 | + --argjson rates "$rates_json" \ |
| 176 | + '{ |
| 177 | + status: $status, |
| 178 | + run_id: $run_id, |
| 179 | + bracket_id: $bracket_id, |
| 180 | + started_at: $started_at, |
| 181 | + suite_driver: $suite_bin, |
| 182 | + ports: { |
| 183 | + probed: ($probed_port | tonumber), |
| 184 | + quicprobe: ($quic_port | tonumber), |
| 185 | + iperf3: ($iperf3_port | tonumber) |
| 186 | + }, |
| 187 | + configuration: { |
| 188 | + datagram_rates: $rates, |
| 189 | + datagram_size_bytes: ($datagram_size | tonumber), |
| 190 | + duration_seconds: ($duration_seconds | tonumber), |
| 191 | + delivery_threshold: ($delivery_threshold | tonumber), |
| 192 | + offered_rate_tolerance: ($offered_rate_tolerance | tonumber), |
| 193 | + process_timeout_ms: ($process_timeout_ms | tonumber), |
| 194 | + datagram_diagnostics: $datagram_diagnostics, |
| 195 | + datagram_drain_limit: ($datagram_drain_limit | tonumber), |
| 196 | + stream_smoke: { |
| 197 | + stream_count: ($stream_count | tonumber), |
| 198 | + payload_size_bytes: ($payload_size | tonumber), |
| 199 | + payload_count: ($payload_count | tonumber) |
| 200 | + } |
| 201 | + }, |
| 202 | + suite_invocations: [] |
| 203 | + }' > "$manifest_path" |
| 204 | + |
| 205 | +record_invocation() { |
| 206 | + local label="$1" |
| 207 | + local kind="$2" |
| 208 | + local rate="$3" |
| 209 | + local tests="$4" |
| 210 | + local api_run_id="$5" |
| 211 | + local exit_status="$6" |
| 212 | + local suite_manifest="$bench_dir/results/$run_id/probed-suite/$api_run_id/manifest.json" |
| 213 | + local status="failed" |
| 214 | + local suite_status="" |
| 215 | + |
| 216 | + if [ -f "$suite_manifest" ]; then |
| 217 | + suite_status="$(jq -r '.status // empty' "$suite_manifest")" |
| 218 | + fi |
| 219 | + |
| 220 | + if [ "$exit_status" -eq 0 ]; then |
| 221 | + status="passed" |
| 222 | + fi |
| 223 | + |
| 224 | + jq -n \ |
| 225 | + --arg label "$label" \ |
| 226 | + --arg kind "$kind" \ |
| 227 | + --arg rate "$rate" \ |
| 228 | + --arg tests "$tests" \ |
| 229 | + --arg api_run_id "$api_run_id" \ |
| 230 | + --arg status "$status" \ |
| 231 | + --arg suite_status "$suite_status" \ |
| 232 | + --arg suite_manifest "$suite_manifest" \ |
| 233 | + --arg result_dir "$bench_dir/results/$run_id/probed-suite/$api_run_id" \ |
| 234 | + --argjson exit_status "$exit_status" \ |
| 235 | + '{ |
| 236 | + label: $label, |
| 237 | + kind: $kind, |
| 238 | + datagram_rate: (if $rate == "" then null else ($rate | tonumber) end), |
| 239 | + tests: ($tests | split(",")), |
| 240 | + api_run_id: $api_run_id, |
| 241 | + status: $status, |
| 242 | + suite_status: (if $suite_status == "" then null else $suite_status end), |
| 243 | + exit_status: $exit_status, |
| 244 | + suite_manifest: $suite_manifest, |
| 245 | + result_dir: $result_dir |
| 246 | + }' >> "$invocations_file" |
| 247 | +} |
| 248 | + |
| 249 | +finish_manifest() { |
| 250 | + local status="$1" |
| 251 | + local finished_at |
| 252 | + local invocations |
| 253 | + |
| 254 | + finished_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)" |
| 255 | + invocations="$(jq -s '.' "$invocations_file")" |
| 256 | + |
| 257 | + jq \ |
| 258 | + --arg status "$status" \ |
| 259 | + --arg finished_at "$finished_at" \ |
| 260 | + --argjson invocations "$invocations" \ |
| 261 | + '. + { |
| 262 | + status: $status, |
| 263 | + finished_at: $finished_at, |
| 264 | + suite_invocations: $invocations |
| 265 | + }' "$manifest_path" > "$manifest_path.tmp" |
| 266 | + mv "$manifest_path.tmp" "$manifest_path" |
| 267 | +} |
| 268 | + |
| 269 | +run_suite() { |
| 270 | + local label="$1" |
| 271 | + local kind="$2" |
| 272 | + local rate="$3" |
| 273 | + local tests="$4" |
| 274 | + local api_run_id="$5" |
| 275 | + local exit_status=0 |
| 276 | + |
| 277 | + printf 'Running %s (%s) as API run %s\n' "$label" "$tests" "$api_run_id" |
| 278 | + |
| 279 | + set +e |
| 280 | + if [ -n "$rate" ]; then |
| 281 | + PROBED_API_RUN_ID="$api_run_id" \ |
| 282 | + PROBED_SUITE_TESTS="$tests" \ |
| 283 | + DATAGRAM_RATE="$rate" \ |
| 284 | + DATAGRAM_SIZE="$datagram_size" \ |
| 285 | + DURATION_SECONDS="$duration_seconds" \ |
| 286 | + DATAGRAM_DRAIN_LIMIT="$datagram_drain_limit" \ |
| 287 | + DATAGRAM_DIAGNOSTICS="$datagram_diagnostics" \ |
| 288 | + DELIVERY_THRESHOLD="$delivery_threshold" \ |
| 289 | + OFFERED_RATE_TOLERANCE="$offered_rate_tolerance" \ |
| 290 | + PROCESS_TIMEOUT_MS="$process_timeout_ms" \ |
| 291 | + "$suite_bin" \ |
| 292 | + --run-id "$run_id" \ |
| 293 | + --tests "$tests" \ |
| 294 | + --probed-port "$probed_port" \ |
| 295 | + --quic-port "$quic_port" \ |
| 296 | + --iperf3-port "$iperf3_port" \ |
| 297 | + --api-run-id "$api_run_id" |
| 298 | + else |
| 299 | + PROBED_API_RUN_ID="$api_run_id" \ |
| 300 | + PROBED_SUITE_TESTS="$tests" \ |
| 301 | + STREAM_COUNT="$stream_count" \ |
| 302 | + PAYLOAD_SIZE="$payload_size" \ |
| 303 | + PAYLOAD_COUNT="$payload_count" \ |
| 304 | + IPERF3_TCP_DURATION="$iperf3_tcp_duration_default" \ |
| 305 | + IPERF3_UDP_DURATION="$iperf3_udp_duration_default" \ |
| 306 | + IPERF3_UDP_BITRATES="$iperf3_udp_bitrates_default" \ |
| 307 | + IPERF3_UDP_LENGTH="$iperf3_udp_length_default" \ |
| 308 | + PROCESS_TIMEOUT_MS="$process_timeout_ms" \ |
| 309 | + "$suite_bin" \ |
| 310 | + --run-id "$run_id" \ |
| 311 | + --tests "$tests" \ |
| 312 | + --probed-port "$probed_port" \ |
| 313 | + --quic-port "$quic_port" \ |
| 314 | + --iperf3-port "$iperf3_port" \ |
| 315 | + --api-run-id "$api_run_id" |
| 316 | + fi |
| 317 | + exit_status=$? |
| 318 | + set -e |
| 319 | + |
| 320 | + record_invocation "$label" "$kind" "$rate" "$tests" "$api_run_id" "$exit_status" |
| 321 | + |
| 322 | + if [ "$exit_status" -ne 0 ]; then |
| 323 | + finish_manifest "failed" |
| 324 | + printf 'DATAGRAM bracket failed at %s. Manifest: %s\n' "$label" "$manifest_path" >&2 |
| 325 | + exit "$exit_status" |
| 326 | + fi |
| 327 | +} |
| 328 | + |
| 329 | +safe_bracket_id="$(printf '%s' "$bracket_id" | tr -c '[:alnum:]_.-' '-')" |
| 330 | +baseline_api_run_id="${run_id}-${safe_bracket_id}-baseline" |
| 331 | + |
| 332 | +run_suite "baseline-stream-smoke" "baseline" "" \ |
| 333 | + "iperf3,reference_stream,moqx_stream" "$baseline_api_run_id" |
| 334 | + |
| 335 | +for rate in "${selected_rates[@]}"; do |
| 336 | + api_run_id="${run_id}-${safe_bracket_id}-dgram-${rate}" |
| 337 | + run_suite "datagram-${rate}" "datagram" "$rate" \ |
| 338 | + "reference_datagram,moqx_datagram" "$api_run_id" |
| 339 | +done |
| 340 | + |
| 341 | +finish_manifest "passed" |
| 342 | + |
| 343 | +printf 'Remote DATAGRAM bracket passed.\n' |
| 344 | +printf 'Infra run id: %s\n' "$run_id" |
| 345 | +printf 'Bracket id: %s\n' "$bracket_id" |
| 346 | +printf 'Rates: %s\n' "$rates" |
| 347 | +printf 'Results dir: %s\n' "$result_dir" |
| 348 | +printf 'Manifest: %s\n' "$manifest_path" |
0 commit comments