Skip to content

Commit 6b9f990

Browse files
committed
Add per-request benchmarking and collection script
Motivation Provide optional, in‑pipeline latency logging in HTTPResponsivenessServer and a straightforward way to gather end‑to‑end percentile metrics. Modifications main.swift Imported Foundation for DispatchTime. Added PerformanceMeasurementHandler (logs “Request handled in XX ms”) and PingHandler (/ping endpoint). Extended channelInitializer and CLI with a --collect-benchmarks flag to insert these handlers only when requested. Examples/collect_benchmarks.sh New Bash script that reads the server’s logs, collects a user‑specified number of samples, uses Python/NumPy to compute p0/p25/p50/p75/p90/p99/p100, and prints a Unicode table. Result Users can now opt in to per‑request latency logging via --collect-benchmarks, and run a one‑step script to produce full percentile reports.
1 parent b910e04 commit 6b9f990

File tree

3 files changed

+297
-81
lines changed

3 files changed

+297
-81
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#!/usr/bin/env bash
2+
#
3+
# collect_benchmarks.sh
4+
#
5+
# Description:
6+
# Reads “Request handled in XX ms” lines from a SwiftNIO HTTPResponsivenessServer
7+
# log file (produced when started with --collect-benchmarks) and computes
8+
# p0, p25, p50, p75, p90, p99 and p100 statistics.
9+
#
10+
# Called from run_benchmarks.sh
11+
#
12+
#
13+
14+
set -euo pipefail
15+
16+
if [ $# -ne 3 ]; then
17+
echo "Usage: $0 <LOGFILE> <ENDPOINT> <SAMPLES>" >&2
18+
exit 1
19+
fi
20+
21+
LOGFILE="$1"
22+
ENDPOINT="$2"
23+
SAMPLES="$3"
24+
25+
# extract exactly the first N timings
26+
mapfile -t times < <(
27+
grep "Request handled in" "$LOGFILE" \
28+
| head -n "$SAMPLES" \
29+
| sed -E 's/.*Request handled in ([0-9]+(\.[0-9]+)?) ms/\1/'
30+
)
31+
32+
if [ "${#times[@]}" -lt "$SAMPLES" ]; then
33+
echo "ERROR: only found ${#times[@]} samples in $LOGFILE" >&2
34+
exit 1
35+
fi
36+
37+
# compute percentiles in Python
38+
python3 - "$ENDPOINT" "${times[@]}" << 'PYCODE'
39+
import sys, numpy as np
40+
41+
# parse float timings from command-line args (skip the first entry which is '-')
42+
data = [float(x) for x in sys.argv[2:]]
43+
arr = np.array(data)
44+
45+
# compute percentiles
46+
pcts = [ np.percentile(arr, p) for p in (0, 25, 50, 75, 90, 99, 100) ]
47+
samples = arr.size
48+
metric = sys.argv[1]
49+
50+
# nice Unicode table
51+
print("╒═══════════════════════╤══════════╤══════════╤══════════╤══════════╤══════════╤══════════╤══════════╤══════════╕")
52+
print("│ Metric │ p0 │ p25 │ p50 │ p75 │ p90 │ p99 │ p100 │ Samples │")
53+
print("╞═══════════════════════╪══════════╪══════════╪══════════╪══════════╪══════════╪══════════╪══════════╪══════════╡")
54+
print(f"│ {metric:20s} │ " +
55+
" │ ".join(f"{v:7.6f}" for v in pcts) +
56+
f" │ {samples:7d} │")
57+
print("╘═══════════════════════╧══════════╧══════════╧══════════╧══════════╧══════════╧══════════╧══════════╧══════════╛")
58+
PYCODE
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#!/usr/bin/env bash
2+
#
3+
# run_benchmarks.sh
4+
#
5+
# Description:
6+
# Sends HTTP GETs to a running HTTPResponsivenessServer (started with --collect-benchmarks)
7+
# then invokes collect-benchmarks.sh on its log.
8+
#
9+
# Prerequisites:
10+
# 1. Build your server with benchmarking support:
11+
# swift build -c release
12+
#
13+
# 2. Start it in the background, redirecting stdout+stderr to a log:
14+
# .build/release/HTTPResponsivenessServer \
15+
# --host 127.0.0.1 \
16+
# --insecure-port 8080 \
17+
# --collect-benchmarks \
18+
# > server.log 2>&1 &
19+
#
20+
# Usage:
21+
# In the root directory of this App
22+
#
23+
# Examples/ping-benchmarks/run_benchmarks.sh \
24+
# --host 127.0.0.1 \
25+
# --port 8080 \
26+
# --endpoint /ping \
27+
# --samples 100 \
28+
# --logfile server.log
29+
#
30+
31+
set -euo pipefail
32+
33+
# --- parse args ---
34+
while [[ $# -gt 0 ]]; do
35+
case $1 in
36+
--host) HOST="$2"; shift 2 ;;
37+
--port) PORT="$2"; shift 2 ;;
38+
--endpoint) ENDPOINT="$2"; shift 2 ;;
39+
--samples) SAMPLES="$2"; shift 2 ;;
40+
--logfile) LOGFILE="$2"; shift 2 ;;
41+
*) echo "Unknown argument: $1" >&2; exit 1 ;;
42+
esac
43+
done
44+
45+
echo "→ Sending $SAMPLES requests to http://$HOST:$PORT$ENDPOINT"
46+
for i in $(seq 1 "$SAMPLES"); do
47+
curl -s "http://$HOST:$PORT$ENDPOINT" > /dev/null
48+
done
49+
50+
# give the server a moment to flush
51+
sleep 0.1
52+
53+
# hand off to the collector
54+
Examples/ping-benchmarks/collect_benchmarks.sh "$LOGFILE" "$ENDPOINT" "$SAMPLES"

0 commit comments

Comments
 (0)