Repository navigation
[CI/Build] Gate CPU and T-One RDMA performance regressions #4639
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
c9addb7
05e8e06
f12b556
1886920
2c7f04e
156cd53
e71d261
a9cea2c
712404c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,151 @@ | ||
| name: Performance regression | ||
|
|
||
| on: | ||
| pull_request: | ||
| branches: [main, 'release/**'] | ||
| types: [opened, synchronize, reopened] | ||
| workflow_dispatch: | ||
| inputs: | ||
| baseline_ref: | ||
| description: Baseline commit or ref (use the candidate SHA for an A/A calibration) | ||
| required: true | ||
| default: main | ||
| candidate_ref: | ||
| description: Candidate commit or ref (empty uses the selected workflow ref) | ||
| required: false | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| concurrency: | ||
| group: performance-${{ github.event.pull_request.number || github.run_id }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| tests: | ||
| name: Performance gate tests | ||
| runs-on: ubuntu-22.04 | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| persist-credentials: false | ||
| - run: python3 -m unittest discover -s scripts/ci/tests -p 'test_*perf*.py' -v | ||
|
|
||
| performance: | ||
| name: Performance Gate | ||
| needs: tests | ||
| if: ${{ always() }} | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| # Fork code always runs on a disposable hosted VM. A repository-owned PR | ||
| # can use the optional dedicated Linux runner label after A/A calibration. | ||
| runs-on: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork && 'ubuntu-22.04' || vars.PERF_RUNNER || 'ubuntu-22.04' }} | ||
| timeout-minutes: 75 | ||
| env: | ||
| PERF_ROOT: ${{ github.workspace }}/performance-${{ github.run_id }}-${{ github.run_attempt }} | ||
| steps: | ||
| - name: Initialize run directory | ||
| run: mkdir -p "$PERF_ROOT/results" | ||
|
|
||
| - name: Require harness tests | ||
| env: | ||
| TEST_RESULT: ${{ needs.tests.result }} | ||
| run: test "$TEST_RESULT" = success | ||
|
|
||
| - name: Checkout candidate | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| ref: ${{ inputs.candidate_ref || github.sha }} | ||
| path: candidate | ||
| fetch-depth: 2 | ||
| submodules: true | ||
| persist-credentials: false | ||
|
|
||
| - name: Checkout baseline | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| ref: ${{ inputs.baseline_ref || github.event.pull_request.base.sha }} | ||
| path: baseline | ||
| submodules: true | ||
| persist-credentials: false | ||
|
|
||
| - name: Freeze the benchmark and policy | ||
| env: | ||
| EVENT_NAME: ${{ github.event_name }} | ||
| run: | | ||
| set -euo pipefail | ||
| baseline_sha=$(git -C baseline rev-parse HEAD) | ||
| candidate_sha=$(git -C candidate rev-parse HEAD) | ||
| if [ "$EVENT_NAME" = pull_request ]; then | ||
| test "$(git -C candidate rev-parse HEAD^1)" = "$baseline_sha" | ||
| fi | ||
| harness_source=baseline | ||
| if [ ! -f baseline/scripts/ci/performance/perf_gate.py ]; then | ||
| harness_source=candidate | ||
| echo '::warning::Bootstrapping the performance harness from the candidate; review the new policy before merging.' | ||
| fi | ||
| mkdir -p "$PERF_ROOT/harness" | ||
| cp -R "$harness_source/scripts/ci/performance/." "$PERF_ROOT/harness/" | ||
| cp baseline/mooncake-store/benchmarks/offset_allocator_concurrency_bench.cpp \ | ||
| candidate/mooncake-store/benchmarks/offset_allocator_concurrency_bench.cpp | ||
|
stmatengss marked this conversation as resolved.
|
||
| python3 "$PERF_ROOT/harness/freeze_build.py" \ | ||
| --baseline baseline --candidate candidate \ | ||
| --manifest "$PERF_ROOT/results/build-config.json" | ||
| echo "BASELINE_SHA=$baseline_sha" >> "$GITHUB_ENV" | ||
| echo "CANDIDATE_SHA=$candidate_sha" >> "$GITHUB_ENV" | ||
| echo "PERF_HARNESS_SHA=$(git -C "$harness_source" rev-parse HEAD)" >> "$GITHUB_ENV" | ||
|
|
||
| - name: Install hosted runner dependencies | ||
| if: runner.environment == 'github-hosted' | ||
| timeout-minutes: 10 | ||
| working-directory: baseline | ||
| run: sudo bash dependencies.sh -y | ||
|
|
||
| - name: Build both revisions with the same Release configuration | ||
| timeout-minutes: 35 | ||
| run: | | ||
| set -euo pipefail | ||
| for revision in baseline candidate; do | ||
| cmake -S "$revision" -B "$revision/build-perf" -G Ninja \ | ||
| -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=c++ \ | ||
| -DBUILD_UNIT_TESTS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_BENCHMARK=ON \ | ||
| -DWITH_STORE_RUST=OFF -DUSE_CUDA=OFF -DUSE_ETCD=OFF \ | ||
| -DSTORE_USE_ETCD=OFF -DENABLE_DEBUG_SYMBOLS=OFF \ | ||
| 2>&1 | tee "$PERF_ROOT/results/$revision-configure.log" | ||
| cmake --build "$revision/build-perf" --parallel 2 \ | ||
| --target offset_allocator_concurrency_bench \ | ||
| 2>&1 | tee "$PERF_ROOT/results/$revision-build.log" | ||
| done | ||
|
|
||
| - name: Collect alternating baseline and candidate samples | ||
| timeout-minutes: 16 | ||
| run: | | ||
| python3 "$PERF_ROOT/harness/perf_gate.py" collect \ | ||
| --baseline baseline/build-perf/mooncake-store/benchmarks/offset_allocator_concurrency_bench \ | ||
| --candidate candidate/build-perf/mooncake-store/benchmarks/offset_allocator_concurrency_bench \ | ||
| --baseline-sha "$BASELINE_SHA" --candidate-sha "$CANDIDATE_SHA" \ | ||
| --collection-timeout-seconds 900 \ | ||
| --output "$PERF_ROOT/results" | ||
|
|
||
| - name: Publish comparison and enforce thresholds | ||
| if: ${{ always() }} | ||
| run: | | ||
| mkdir -p "$PERF_ROOT/results" | ||
| if [ ! -f "$PERF_ROOT/harness/perf_gate.py" ]; then | ||
| echo '## Performance Gate: ERROR — setup or harness tests failed' > "$PERF_ROOT/results/summary.md" | ||
| cat "$PERF_ROOT/results/summary.md" >> "$GITHUB_STEP_SUMMARY" | ||
| echo '::error::Performance gate setup failed; no valid measurement is available.' | ||
| exit 2 | ||
| fi | ||
| cp "$PERF_ROOT/harness/policy.json" "$PERF_ROOT/results/policy.json" | ||
| python3 "$PERF_ROOT/harness/perf_gate.py" compare \ | ||
| --baseline "$PERF_ROOT/results/baseline.json" --candidate "$PERF_ROOT/results/candidate.json" \ | ||
| --baseline-sha "${BASELINE_SHA:-}" --candidate-sha "${CANDIDATE_SHA:-}" \ | ||
| --output "$PERF_ROOT/results" --summary "$GITHUB_STEP_SUMMARY" | ||
|
|
||
| - name: Preserve raw samples and diagnostics | ||
| if: ${{ always() }} | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: performance-results | ||
| path: ${{ env.PERF_ROOT }}/results/ | ||
| if-no-files-found: error | ||
| retention-days: 14 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| name: RDMA performance regression | ||
|
|
||
| on: | ||
| pull_request: | ||
| branches: [main, 'release/**'] | ||
| types: [opened, synchronize, reopened] | ||
| workflow_dispatch: | ||
| inputs: | ||
| baseline_sha: | ||
| description: Full baseline commit SHA (same as candidate for A/A calibration) | ||
| required: true | ||
| candidate_sha: | ||
| description: Full candidate commit SHA | ||
| required: true | ||
| workflow_call: | ||
| inputs: | ||
| baseline_sha: | ||
| required: true | ||
| type: string | ||
| candidate_sha: | ||
| required: true | ||
| type: string | ||
| secrets: | ||
| TONE_USER_NAME: | ||
| required: true | ||
| TONE_USER_TOKEN: | ||
| required: true | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| # One fixed hardware pair; retain up to 100 waiting runs without interrupting it. | ||
| concurrency: | ||
| group: rdma-performance-pair | ||
| cancel-in-progress: false | ||
| queue: max | ||
|
|
||
| jobs: | ||
| rdma: | ||
| name: RDMA Performance Gate | ||
| if: ${{ github.event_name != 'pull_request' || vars.RDMA_PERF_ENABLED == 'true' }} | ||
| runs-on: ubuntu-22.04 | ||
| timeout-minutes: 60 | ||
| steps: | ||
| - name: Checkout the reviewed harness | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| # Never execute candidate code in the credential-bearing controller. | ||
| # Manual bootstrap uses the selected workflow revision, reviewed by its dispatcher. | ||
| ref: ${{ github.event.pull_request.base.sha || github.workflow_sha }} | ||
| persist-credentials: false | ||
|
|
||
| - name: Submit, collect, and enforce RDMA thresholds | ||
| env: | ||
| BASELINE_SHA: ${{ inputs.baseline_sha || github.event.pull_request.base.sha }} | ||
| CANDIDATE_SHA: ${{ inputs.candidate_sha || github.sha }} | ||
| TONE_USER_NAME: ${{ secrets.TONE_USER_NAME }} | ||
| TONE_USER_TOKEN: ${{ secrets.TONE_USER_TOKEN }} | ||
| TONE_WORKSPACE: ${{ vars.TONE_WORKSPACE }} | ||
| TONE_PROJECT: ${{ vars.TONE_PROJECT }} | ||
| TONE_RDMA_TEMPLATE: ${{ vars.TONE_RDMA_TEMPLATE }} | ||
| TONE_RESULT_ORIGIN: ${{ vars.TONE_RESULT_ORIGIN }} | ||
| RUN_ID: ${{ github.run_id }}-${{ github.run_attempt }} | ||
| run: | | ||
| python3 scripts/ci/performance/tone_rdma.py \ | ||
| --baseline-sha "$BASELINE_SHA" --candidate-sha "$CANDIDATE_SHA" \ | ||
| --harness-sha "$(git rev-parse HEAD)" --run-id "$RUN_ID" \ | ||
| --output rdma-performance-results | ||
|
|
||
| - name: Publish setup errors | ||
| if: ${{ always() }} | ||
| run: | | ||
| if [ ! -f rdma-performance-results/summary.md ]; then | ||
| mkdir -p rdma-performance-results | ||
| echo '## RDMA Performance Gate: ERROR — no complete report was returned' \ | ||
| > rdma-performance-results/summary.md | ||
| cat rdma-performance-results/summary.md >> "$GITHUB_STEP_SUMMARY" | ||
| echo '::error::RDMA setup failed or the run was interrupted.' | ||
| exit 2 | ||
| fi | ||
|
|
||
| - name: Preserve results even on failure | ||
| if: ${{ always() }} | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: rdma-performance-results | ||
| path: rdma-performance-results/ | ||
| if-no-files-found: error | ||
| retention-days: 14 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no
pathsfilter, so docs-only or Python-only PRs also pay for two Release builds plus up to 15 minutes of benchmarking. Hosted-runner noise can then turn into an ERROR on a change that cannot affect the allocator. Could we limit this tomooncake-store/**,mooncake-common/**, top-level CMake andscripts/ci/performance/**? If the check is meant to become required, a small no-op job for skipped paths keeps it reporting.