@@ -1157,48 +1157,77 @@ jobs:
11571157 # warmup-then-measure cycles run back-to-back with no other
11581158 # lib's bench process in between, so each measurement sees a
11591159 # comparable warm-VM state.
1160- - name : Bench rustVX-PR (warmup + measure )
1160+ - name : Bench + perf gate (with retry for VM noise )
11611161 run : |
1162- set -eo pipefail
1162+ set -uo pipefail
11631163 # NB: not using `-u` because `$LD_LIBRARY_PATH` is unset in a
11641164 # fresh step and the trailing `:${LD_LIBRARY_PATH:-}` default
11651165 # would still trip `-u` in some bash variants.
1166- cd ${{ github.workspace }}/openvx-mark/build-pr
1167- export LD_LIBRARY_PATH=${{ steps.pr_rustvx.outputs.lib_dir }}
1168- # Throwaway: prime instruction/data caches and any
1169- # is_x86_feature_detected! one-time-dispatch overhead.
1170- ./openvx-mark --resolution FHD --iterations 5 --warmup 0 \
1171- --output /tmp/warmup-pr-throwaway >/dev/null 2>&1 || true
1172- # Real measurement.
1173- ./openvx-mark --resolution FHD --iterations 20 --warmup 5
11741166
1175- - name : Bench rustVX-main (warmup + measure)
1176- run : |
1177- set -eo pipefail
1178- cd ${{ github.workspace }}/openvx-mark/build-main
1179- export LD_LIBRARY_PATH=${{ steps.main_rustvx.outputs.lib_dir }}
1180- ./openvx-mark --resolution FHD --iterations 5 --warmup 0 \
1181- --output /tmp/warmup-main-throwaway >/dev/null 2>&1 || true
1182- ./openvx-mark --resolution FHD --iterations 20 --warmup 5
1183-
1184- - name : Run perf gate
1185- run : |
1186- set -euo pipefail
1187- PR=${{ github.workspace }}/openvx-mark/build-pr/benchmark_results/benchmark_results.json
1188- MAIN=${{ github.workspace }}/openvx-mark/build-main/benchmark_results/benchmark_results.json
1189- if [ ! -f "$PR" ] || [ ! -f "$MAIN" ]; then
1190- echo "::error::Missing benchmark JSONs (PR=$PR, MAIN=$MAIN)."
1191- ls -la "$(dirname "$PR")" "$(dirname "$MAIN")" 2>/dev/null || true
1192- exit 1
1193- fi
1194-
1195- python3 ${{ github.workspace }}/.github/scripts/perf_gate.py \
1196- "$MAIN" "$PR" \
1197- --geomean-floor 0.97 \
1198- --kernel-floor 0.90 \
1199- --warn-floor 0.95 \
1200- --max-cv 5.0 \
1201- --summary-out "$GITHUB_STEP_SUMMARY"
1167+ PR_LIB=${{ steps.pr_rustvx.outputs.lib_dir }}
1168+ MAIN_LIB=${{ steps.main_rustvx.outputs.lib_dir }}
1169+ PR_BUILD=${{ github.workspace }}/openvx-mark/build-pr
1170+ MAIN_BUILD=${{ github.workspace }}/openvx-mark/build-main
1171+ PR_JSON=$PR_BUILD/benchmark_results/benchmark_results.json
1172+ MAIN_JSON=$MAIN_BUILD/benchmark_results/benchmark_results.json
1173+
1174+ MAX_RETRIES=3
1175+ for attempt in $(seq 1 $MAX_RETRIES); do
1176+ echo ""
1177+ echo "=== Perf gate attempt $attempt / $MAX_RETRIES ==="
1178+ echo ""
1179+
1180+ # Bench PR
1181+ cd "$PR_BUILD"
1182+ export LD_LIBRARY_PATH=$PR_LIB
1183+ ./openvx-mark --resolution FHD --iterations 5 --warmup 0 \
1184+ --output /tmp/warmup-pr-throwaway-$attempt >/dev/null 2>&1 || true
1185+ ./openvx-mark --resolution FHD --iterations 20 --warmup 5
1186+
1187+ # Bench main
1188+ cd "$MAIN_BUILD"
1189+ export LD_LIBRARY_PATH=$MAIN_LIB
1190+ ./openvx-mark --resolution FHD --iterations 5 --warmup 0 \
1191+ --output /tmp/warmup-main-throwaway-$attempt >/dev/null 2>&1 || true
1192+ ./openvx-mark --resolution FHD --iterations 20 --warmup 5
1193+
1194+ # Run gate
1195+ if [ ! -f "$PR_JSON" ] || [ ! -f "$MAIN_JSON" ]; then
1196+ echo "::error::Missing benchmark JSONs on attempt $attempt."
1197+ ls -la "$(dirname "$PR_JSON")" "$(dirname "$MAIN_JSON")" 2>/dev/null || true
1198+ if [ $attempt -eq $MAX_RETRIES ]; then exit 1; fi
1199+ continue
1200+ fi
1201+
1202+ # Run perf gate (set +e to capture exit code without failing)
1203+ set +e
1204+ python3 ${{ github.workspace }}/.github/scripts/perf_gate.py \
1205+ "$MAIN_JSON" "$PR_JSON" \
1206+ --geomean-floor 0.97 \
1207+ --kernel-floor 0.90 \
1208+ --warn-floor 0.95 \
1209+ --max-cv 5.0 \
1210+ --summary-out "$GITHUB_STEP_SUMMARY"
1211+ gate_exit=$?
1212+ set -e
1213+
1214+ if [ $gate_exit -eq 0 ]; then
1215+ echo ""
1216+ echo "✅ Perf gate PASSED on attempt $attempt"
1217+ echo ""
1218+ exit 0
1219+ else
1220+ echo ""
1221+ echo "⚠️ Perf gate FAILED on attempt $attempt"
1222+ echo ""
1223+ # Clean up old results so next iteration gets fresh JSONs
1224+ rm -f "$PR_JSON" "$MAIN_JSON"
1225+ if [ $attempt -eq $MAX_RETRIES ]; then
1226+ echo "::error::Perf gate failed after $MAX_RETRIES attempts. Likely real regression."
1227+ exit 1
1228+ fi
1229+ fi
1230+ done
12021231
12031232 - name : Upload PR rustVX benchmark results (perf-gate)
12041233 if : always()
@@ -1215,3 +1244,12 @@ jobs:
12151244 name : perf-gate-results-main
12161245 path : ${{ github.workspace }}/openvx-mark/build-main/benchmark_results/
12171246 if-no-files-found : ignore
1247+
1248+ # Save step summary for all attempts, including intermediate failures
1249+ - name : Upload perf gate step summary
1250+ if : always()
1251+ uses : actions/upload-artifact@v4
1252+ with :
1253+ name : perf-gate-step-summary
1254+ path : ${{ github.workspace }}/perf_gate_attempt_*.md
1255+ if-no-files-found : ignore
0 commit comments