# Copyright 2024 RustFS Team # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Warp A/B budget gate for the hotpath series (rustfs/backlog#935 HP-14, item 4). # # Two entry points, honestly scoped: # * schedule (nightly, on main): post-merge detection — catches a regression # within 24h of landing, not before merge. # * pull_request labeled `perf-ab`: opt-in pre-merge gate for a specific PR. # The `perf-deliberate-tradeoff` label runs the gate with --allow-regression so # a deliberate correctness cost (e.g. the #4221 fsync durability fix) is # recorded but does not block (rustfs/backlog#935 correction 1). name: Performance A/B on: schedule: - cron: "0 6 * * *" # 06:00 UTC nightly, against main workflow_dispatch: inputs: duration: description: "warp duration per round" required: false default: "30s" type: string allow_regression: description: "Pass the gate despite a FAIL (deliberate tradeoff)" required: false default: false type: boolean pull_request: types: [labeled, synchronize, reopened] permissions: contents: read pull-requests: write env: CARGO_TERM_COLOR: always RUST_BACKTRACE: 1 jobs: warp-ab: name: Warp A/B budget gate # Opt-in on PRs: only run when the `perf-ab` label is present. Always run on # schedule / manual dispatch. if: >- github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'perf-ab') runs-on: sm-standard-2 timeout-minutes: 90 steps: - name: Checkout repository uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 with: fetch-depth: 0 # baseline is built from origin/main - name: Setup Rust environment uses: ./.github/actions/setup with: rust-version: stable cache-shared-key: warp-ab-${{ hashFiles('**/Cargo.lock') }} cache-save-if: ${{ github.ref == 'refs/heads/main' }} github-token: ${{ secrets.GITHUB_TOKEN }} - name: Install warp run: | set -euo pipefail WARP_VERSION="1.0.0" curl -fsSL "https://github.com/minio/warp/releases/download/v${WARP_VERSION}/warp_Linux_x86_64.tar.gz" \ | sudo tar -xz -C /usr/local/bin warp warp --version - name: Decide exemption id: exempt run: | allow="false" if [[ "${{ github.event_name }}" == "pull_request" ]] \ && ${{ contains(github.event.pull_request.labels.*.name, 'perf-deliberate-tradeoff') }}; then allow="true" fi if [[ "${{ github.event.inputs.allow_regression }}" == "true" ]]; then allow="true" fi echo "allow_regression=$allow" >> "$GITHUB_OUTPUT" - name: Run warp A/B and gate id: ab run: | set -euo pipefail args=(--baseline-ref origin/main --duration "${{ github.event.inputs.duration || '30s' }}") if [[ "${{ steps.exempt.outputs.allow_regression }}" == "true" ]]; then args+=(--allow-regression --exemption-reason "labeled perf-deliberate-tradeoff / dispatch override") fi # Do not let a gate FAIL abort the job here; capture status and surface # it after the PR comment is posted. set +e bash scripts/run_hotpath_warp_ab.sh "${args[@]}" echo "status=$?" >> "$GITHUB_OUTPUT" set -e # Locate the newest gate.md for the comment/artifact steps. gate_md="$(ls -t target/hotpath-ab/*/gate.md 2>/dev/null | head -n1 || true)" echo "gate_md=$gate_md" >> "$GITHUB_OUTPUT" - name: Upload A/B results if: always() uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: hotpath-warp-ab-${{ github.run_number }} path: target/hotpath-ab/ if-no-files-found: warn - name: Comment gate result on PR if: always() && github.event_name == 'pull_request' && steps.ab.outputs.gate_md != '' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | gh pr comment "${{ github.event.pull_request.number }}" --body-file "${{ steps.ab.outputs.gate_md }}" - name: Enforce gate if: always() run: | status="${{ steps.ab.outputs.status }}" if [[ "$status" != "0" ]]; then echo "::error::warp A/B budget gate failed (exit $status). See the PR comment / gate.md artifact." >&2 exit "$status" fi echo "warp A/B budget gate passed."