Fix S-101 multipoint sounding glyphs collapsing onto one anchor #286
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Performance | |
| on: | |
| pull_request: | |
| branches: [main] | |
| jobs: | |
| perf-gate: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: '10.0.x' | |
| # --- Build the BASE branch's PerfRunner into a dedicated dir --- | |
| - name: Checkout base branch | |
| run: git checkout ${{ github.event.pull_request.base.sha }} | |
| # The perf tooling on the base SHA may predate this PR's CLI | |
| # surface (--out-subdir, --append, --round-tag, --side, --scenarios) | |
| # and the perf.iteration activity instrumentation the gate reads. | |
| # Overlay the PR's perf tooling + the tiny Diagnostics.Export delta | |
| # (an --append overload on AddFileExporter) onto the base tree so | |
| # the base runner is built with this PR's runner code linked against | |
| # the base SHA's library code. The library code under test stays | |
| # at the base SHA — only the measurement harness is overlaid. | |
| # | |
| # Directory.Packages.props is overlaid as well because central | |
| # package management requires every PackageReference in the | |
| # overlaid PerfRunner csproj to have a matching PackageVersion; | |
| # if the PR adds a new package (e.g. profiler dependencies) the | |
| # base CPM file will not contain it and restore will fail. | |
| - name: Overlay PR perf tooling onto base tree | |
| run: | | |
| git checkout ${{ github.event.pull_request.head.sha }} -- \ | |
| tools/EncDotNet.S100.PerfRunner \ | |
| tools/EncDotNet.S100.PerfReport \ | |
| tools/perf \ | |
| src/EncDotNet.S100.Crs.ProjNet \ | |
| src/EncDotNet.S100.Diagnostics.Export \ | |
| Directory.Packages.props | |
| - name: Build base PerfRunner | |
| run: | | |
| dotnet publish tools/EncDotNet.S100.PerfRunner/EncDotNet.S100.PerfRunner.csproj \ | |
| --configuration Release \ | |
| --output /tmp/perf-bin/base \ | |
| --no-self-contained | |
| # --- Build the PR branch's PerfRunner into a separate dir --- | |
| - name: Checkout PR branch | |
| run: git checkout ${{ github.event.pull_request.head.sha }} | |
| - name: Build candidate PerfRunner | |
| run: | | |
| dotnet publish tools/EncDotNet.S100.PerfRunner/EncDotNet.S100.PerfRunner.csproj \ | |
| --configuration Release \ | |
| --output /tmp/perf-bin/cand \ | |
| --no-self-contained | |
| # --- Build the PerfReport tool from the PR branch (gate logic) --- | |
| - name: Build PerfReport | |
| run: | | |
| dotnet build tools/EncDotNet.S100.PerfReport/EncDotNet.S100.PerfReport.csproj \ | |
| --configuration Release | |
| # --- Interleaved measurement: 5 rounds × 4 iters/side = 20 samples/side --- | |
| - name: Run interleaved performance measurements | |
| run: | | |
| tools/perf/interleave.sh \ | |
| --base-runner /tmp/perf-bin/base/EncDotNet.S100.PerfRunner.dll \ | |
| --cand-runner /tmp/perf-bin/cand/EncDotNet.S100.PerfRunner.dll \ | |
| --base-out /tmp/perf-baseline \ | |
| --cand-out /tmp/perf-candidate \ | |
| --corpus tests/datasets \ | |
| --rounds 5 \ | |
| --iters 4 \ | |
| --warmup 3 \ | |
| --subdir interleaved | |
| # --- First gate pass (median + MAD; suspicious zone allowed) --- | |
| - name: Run performance gate (first pass) | |
| id: gate1 | |
| run: | | |
| dotnet run --no-build --configuration Release \ | |
| --project tools/EncDotNet.S100.PerfReport -- \ | |
| gate \ | |
| /tmp/perf-baseline/interleaved \ | |
| /tmp/perf-candidate/interleaved \ | |
| --threshold 10 \ | |
| --min-abs 100 \ | |
| --mad-k 3.0 \ | |
| --retry-zone-mult 2.0 \ | |
| --out /tmp/perf-gate.md | |
| if [[ -s /tmp/perf-gate.md.suspicious.txt ]]; then | |
| echo "suspicious=$(tr '\n' ',' < /tmp/perf-gate.md.suspicious.txt | sed 's/,$//')" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "suspicious=" >> "$GITHUB_OUTPUT" | |
| fi | |
| # --- Retry only the suspicious scenarios with extra rounds --- | |
| - name: Re-test suspicious scenarios | |
| if: steps.gate1.outputs.suspicious != '' | |
| run: | | |
| echo "Re-testing scenarios: ${{ steps.gate1.outputs.suspicious }}" | |
| tools/perf/interleave.sh \ | |
| --base-runner /tmp/perf-bin/base/EncDotNet.S100.PerfRunner.dll \ | |
| --cand-runner /tmp/perf-bin/cand/EncDotNet.S100.PerfRunner.dll \ | |
| --base-out /tmp/perf-baseline \ | |
| --cand-out /tmp/perf-candidate \ | |
| --corpus tests/datasets \ | |
| --rounds 5 \ | |
| --iters 4 \ | |
| --warmup 3 \ | |
| --subdir interleaved \ | |
| --scenarios "${{ steps.gate1.outputs.suspicious }}" | |
| # --- Final gate (no retry zone — suspicious scenarios now have ≥40 samples) --- | |
| - name: Run performance gate (final) | |
| if: steps.gate1.outputs.suspicious != '' | |
| run: | | |
| dotnet run --no-build --configuration Release \ | |
| --project tools/EncDotNet.S100.PerfReport -- \ | |
| gate \ | |
| /tmp/perf-baseline/interleaved \ | |
| /tmp/perf-candidate/interleaved \ | |
| --threshold 10 \ | |
| --min-abs 100 \ | |
| --mad-k 3.0 \ | |
| --retry-zone-mult 1.0 \ | |
| --out /tmp/perf-gate.md | |
| - name: Upload gate report | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: perf-gate-report | |
| path: | | |
| /tmp/perf-gate.md | |
| /tmp/perf-gate.md.suspicious.txt | |
| /tmp/perf-baseline/interleaved/ | |
| /tmp/perf-candidate/interleaved/ | |
| if-no-files-found: ignore | |
| - name: Post PR comment | |
| if: always() && github.event_name == 'pull_request' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| const path = '/tmp/perf-gate.md'; | |
| if (!fs.existsSync(path)) { | |
| console.log('No gate report found, skipping comment.'); | |
| return; | |
| } | |
| const body = fs.readFileSync(path, 'utf8'); | |
| const marker = '<!-- perf-gate-comment -->'; | |
| const fullBody = `${marker}\n${body}`; | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| }); | |
| const existing = comments.find(c => c.body?.includes(marker)); | |
| if (existing) { | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: existing.id, | |
| body: fullBody, | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: fullBody, | |
| }); | |
| } |