Skip to content

Commit 0f07e5d

Browse files
committed
Add probed datagram bracket runner
1 parent be67caa commit 0f07e5d

5 files changed

Lines changed: 511 additions & 0 deletions

File tree

bench/probed/PLAYBOOK.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,23 @@ DURATION_SECONDS=1 \
228228
just bench-transport-probed-suite <run-id>
229229
```
230230

231+
For the #40 ARM DATAGRAM validation, use the bracket wrapper after the lab is
232+
up, private-path checked, and tools are deployed:
233+
234+
```bash
235+
just bench-transport-probed-datagram-bracket <run-id> 30000,32000
236+
```
237+
238+
The wrapper runs one baseline/stream-smoke suite
239+
(`iperf3,reference_stream,moqx_stream`) and then one DATAGRAM suite
240+
(`reference_datagram,moqx_datagram`) per requested rate. The default bracket
241+
uses 1180-byte DATAGRAMs, 3-second paced steps, delivery threshold 0.95, and
242+
offered-rate tolerance 0.95. It writes an aggregate manifest under:
243+
244+
```text
245+
bench/moqxprobe/results/<infra-run-id>/probed-datagram-bracket/<bracket-id>/
246+
```
247+
231248
Useful suite knobs:
232249

233250
```text

bench/probed/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,22 @@ DURATION_SECONDS=1 \
242242
just bench-transport-probed-suite <run-id>
243243
```
244244

245+
For the current #40 validation loop, prefer the bracket wrapper once the lab is
246+
already provisioned, private-path checked, and tools are deployed:
247+
248+
```bash
249+
just bench-transport-probed-datagram-bracket <run-id> 30000,32000
250+
```
251+
252+
It runs `iperf3,reference_stream,moqx_stream` once, then runs
253+
`reference_datagram,moqx_datagram` once per requested DATAGRAM rate. Defaults
254+
are tuned for the ARM near-limit check: 1180-byte DATAGRAMs, 3-second paced
255+
steps, delivery threshold 0.95, and offered-rate tolerance 0.95. It writes an
256+
aggregate manifest under
257+
`bench/moqxprobe/results/<run-id>/probed-datagram-bracket/<bracket-id>/` while
258+
leaving each underlying `remote_curl_suite.sh` run under the existing
259+
`probed-suite/<api-run-id>/` layout.
260+
245261
When iterating on `moqxprobe`, prefer the update-and-run loop:
246262

247263
```bash
Lines changed: 348 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
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

Comments
 (0)