3232 name : Stress Benchmark
3333 runs-on : ubuntu-latest
3434 timeout-minutes : 15
35- continue-on-error : true
3635 env :
3736 # Tuned for 4 vCPU / 16 GB CI runners to complete within 5 minutes.
3837 # Code defaults are 10 components / 35 workers.
@@ -73,11 +72,23 @@ jobs:
7372
7473 - name : Run stress benchmark
7574 id : bench
75+ continue-on-error : true
7676 run : |
7777 set -o pipefail
7878 cd benchmark/stress
7979 ./stress 2>benchmark-stderr.txt | tee benchmark-output.txt
8080
81+ - name : Compare against baseline
82+ id : compare
83+ if : steps.bench.outcome == 'success'
84+ run : |
85+ cd benchmark/stress
86+ if [[ -f baseline.json ]]; then
87+ ./compare.sh benchmark-output.txt
88+ else
89+ echo "No baseline found, skipping comparison."
90+ fi
91+
8192 - name : Write job summary
8293 if : always()
8394 run : |
@@ -103,25 +114,58 @@ jobs:
103114 exit 0
104115 fi
105116
106- ns_op=$(echo "$line" | grep -oP '[\d.]+ ns/op' | awk '{print $1}')
107- peak_rss=$(echo "$line" | grep -oP '[\d.]+ peak-RSS-bytes' | awk '{print $1}')
108- alloc=$(echo "$line" | grep -oP '[\d.]+ allocated-bytes/op' | awk '{print $1}')
109- heap=$(echo "$line" | grep -oP '[\d.]+ heap-bytes-from-system' | awk '{print $1}')
117+ read -r ns_op peak_rss alloc heap < <(BENCH_LINE="$line" python3 -c "
118+ import os, re
119+ line = os.environ['BENCH_LINE']
120+ def val(p):
121+ m = re.search(p, line)
122+ return m.group(1) if m else '0'
123+ print(val(r'([\d.]+)\s+ns/op'), val(r'([\d.]+)\s+peak-RSS-bytes'), val(r'([\d.]+)\s+allocated-bytes/op'), val(r'([\d.]+)\s+heap-bytes-from-system'))
124+ ")
110125
111126 secs=$(awk -v val="${ns_op:-0}" 'BEGIN {printf "%.1f", val / 1000000000}')
112127 rss_mb=$(awk -v val="${peak_rss:-0}" 'BEGIN {printf "%.0f", val / 1048576}')
113128 alloc_mb=$(awk -v val="${alloc:-0}" 'BEGIN {printf "%.0f", val / 1048576}')
114129 heap_mb=$(awk -v val="${heap:-0}" 'BEGIN {printf "%.0f", val / 1048576}')
115130
131+ has_baseline=false
132+ if [[ -f benchmark/stress/baseline.json ]]; then
133+ has_baseline=true
134+ bl_rss=$(python3 -c "import json; print(json.load(open('benchmark/stress/baseline.json'))['peak_rss_bytes'])")
135+ bl_ns=$(python3 -c "import json; print(json.load(open('benchmark/stress/baseline.json'))['ns_per_op'])")
136+ bl_rss_mb=$(awk -v val="$bl_rss" 'BEGIN {printf "%.0f", val / 1048576}')
137+ bl_secs=$(awk -v val="$bl_ns" 'BEGIN {printf "%.1f", val / 1000000000}')
138+ rss_change=$(awk -v cur="$peak_rss" -v base="$bl_rss" 'BEGIN {printf "%+.1f", ((cur - base) / base) * 100}')
139+ time_change=$(awk -v cur="$ns_op" -v base="$bl_ns" 'BEGIN {printf "%+.1f", ((cur - base) / base) * 100}')
140+ fi
141+
116142 {
117143 echo "## Stress Benchmark"
118144 echo ""
119- echo "| Metric | Value | Description |"
120- echo "|--------|-------|-------------|"
121- echo "| Components | ${EC_STRESS_COMPONENTS} | Snapshot components validated |"
122- echo "| Workers | ${EC_STRESS_WORKERS} | Parallel validation workers |"
123- echo "| Execution time | ${secs}s | Wall-clock time per iteration |"
124- echo "| Peak RSS | ${rss_mb} MB | Max physical memory used |"
125- echo "| Allocated memory | ${alloc_mb} MB | Total Go heap allocations |"
126- echo "| Heap from system | ${heap_mb} MB | Heap memory requested from OS |"
145+ if [[ "$has_baseline" == "true" ]]; then
146+ echo "| Metric | Current | Baseline | Change | Description |"
147+ echo "|--------|---------|----------|--------|-------------|"
148+ echo "| Components | ${EC_STRESS_COMPONENTS} | | | Snapshot components validated |"
149+ echo "| Workers | ${EC_STRESS_WORKERS} | | | Parallel validation workers |"
150+ echo "| Execution time | ${secs}s | ${bl_secs}s | ${time_change}% | Wall-clock time per iteration |"
151+ echo "| Peak RSS | ${rss_mb} MB | ${bl_rss_mb} MB | ${rss_change}% | Max physical memory used |"
152+ echo "| Allocated memory | ${alloc_mb} MB | | | Total Go heap allocations |"
153+ echo "| Heap from system | ${heap_mb} MB | | | Heap memory requested from OS |"
154+ else
155+ echo "| Metric | Value | Description |"
156+ echo "|--------|-------|-------------|"
157+ echo "| Components | ${EC_STRESS_COMPONENTS} | Snapshot components validated |"
158+ echo "| Workers | ${EC_STRESS_WORKERS} | Parallel validation workers |"
159+ echo "| Execution time | ${secs}s | Wall-clock time per iteration |"
160+ echo "| Peak RSS | ${rss_mb} MB | Max physical memory used |"
161+ echo "| Allocated memory | ${alloc_mb} MB | Total Go heap allocations |"
162+ echo "| Heap from system | ${heap_mb} MB | Heap memory requested from OS |"
163+ fi
164+ if [[ "${{ steps.compare.outcome }}" == "failure" ]]; then
165+ echo ""
166+ echo "> **⚠️ Performance regression detected.** Update the baseline with \`make generate-baseline\` if this is expected."
167+ elif [[ "${{ steps.compare.outcome }}" == "skipped" ]]; then
168+ echo ""
169+ echo "> **ℹ️ Baseline comparison skipped** because the benchmark step failed."
170+ fi
127171 } >> "$GITHUB_STEP_SUMMARY"
0 commit comments