Wie Bencher in GitHub-Aktionen verwendet wird


on:
  push:
    branches: main

jobs:
  benchmark_with_bencher:
    name: Continuous Benchmarking with Bencher
    runs-on: ubuntu-latest
    env:
      BENCHER_PROJECT: save-walter-white
      BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }}
      BENCHER_TESTBED: ubuntu-latest
      BENCHER_ADAPTER: json
    steps:
      - uses: actions/checkout@v3
      - uses: bencherdev/bencher@main
      - name: Track Benchmarks with Bencher
        run: |
          bencher run \
          --branch main \
          --err \
          "bencher mock"
  1. Erstellen Sie eine GitHub Actions workflow Datei. (z.B.: .github/workflows/benchmark.yml)
  2. Führen Sie push Events zum main Zweig durch. Siehe GitHub Actions on Dokumentation für einen vollständigen Überblick. Siehe auch Pull Requests unten.
  3. Erstellen Sie eine GitHub Actions job. (z.B.: benchmark_with_bencher)
  4. Das Projekt muss bereits existieren. Setzen Sie das --project Flag oder die BENCHER_PROJECT Umgebungsvariable auf den Projektslug oder UUID (z.B.: BENCHER_PROJECT: save-walter-white).
  5. Das API-Token muss bereits existieren. Fügen Sie BENCHER_API_TOKEN als Repository Geheimnis hinzu. (z.B.: Repo -> Einstellungen -> Geheimnisse und Variablen -> Aktionen -> Neues Repository-Geheimnis) Setzen Sie das --token Flag oder die BENCHER_API_TOKEN Umgebungsvariable auf das API-Token. (z.B.: BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }})
  6. Optional: Setzen Sie das --testbed Flag oder die BENCHER_TESTBED Umgebungsvariable auf den Testbed Slug oder UUID. (z.B.: BENCHER_TESTBED: ubuntu-latest) Das Testbed muss bereits existieren. Wird dies nicht gesetzt, wird das localhost Testbed verwendet.
  7. Optional: Setzen Sie das --adapter Flag oder die BENCHER_ADAPTER Umgebungsvariable auf den gewünschten Adapternamen. (z.B.: BENCHER_ADAPTER: json) Wird dies nicht gesetzt, wird der magic Adapter verwendet. Siehe Benchmark Harness Adapter für einen vollständigen Überblick.
  8. Checken Sie Ihren Quellcode aus. (z.B.: uses: actions/checkout@v3)
  9. Installieren Sie die Bencher CLI mit der GitHub Action. (z.B.: uses: bencherdev/bencher@main)
  10. Verfolgen Sie Ihre Benchmarks mit dem bencher run CLI-Unterbefehl:
    1. Optional: Setzen Sie das --branch Flag oder die BENCHER_BRANCH Umgebungsvariable auf den Branch Slug oder UUID. (z.B.: --branch main) Der Branch muss bereits existieren. Wird dies nicht gesetzt, wird der main Branch verwendet.
    2. Setzen Sie den Befehl zum Fehlschlagen, wenn ein Alarm generiert wird. (z.B.: --err) Damit ein Alarm generiert wird, muss bereits ein Threshold existieren.
    3. Führen Sie Ihre Benchmarks durch und erzeugen Sie einen Bericht aus den Ergebnissen. (z.B.: "bencher mock")

Pull-Anfragen

Um eine Performance-Regression in Pull-Anfragen zu erkennen, müssen Sie Ihre Benchmarks bei den PRs durchführen. Wenn Sie nur erwarten, dass Sie PRs von Zweigen innerhalb des gleichen Repositories haben, können Sie das oben stehende Beispiel einfach ändern, um auch bei pull_request Events zu laufen.

⚠️ Diese Lösung funktioniert nur, wenn alle PRs aus dem gleichen Repository stammen! Siehe Pull-Anfragen von Forks unten.

on:
  push:
    branches: main
  pull_request:

jobs:
  benchmark_with_bencher:
    name: Continuous Benchmarking with Bencher
    runs-on: ubuntu-latest
    env:
      BENCHER_PROJECT: save-walter-white
      BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }}
      BENCHER_TESTBED: ubuntu-latest
      BENCHER_ADAPTER: json
    steps:
      - uses: actions/checkout@v3
      - uses: bencherdev/bencher@main
      - name: Track Benchmarks with Bencher
        run: |
          bencher run \
          --if-branch "$GITHUB_REF_NAME" \
          --else-if-branch "$GITHUB_BASE_REF" \
          --else-if-branch main \
          --github-actions ${{ secrets.GITHUB_TOKEN }} \
          --err \
          "bencher mock"
  1. Führen Sie push Events zum main Zweig und auf pull_request Events aus. Es ist wichtig, das Laufen bei push nur auf die ausgewählten Zweige zu beschränken (z.B.: main), um zu verhindern, dass Pushes zu PR-Zweigen doppelt ausgeführt werden!
  2. Verwenden Sie statt dem main Zweig immer die standardmäßigen Umgebungsvariablen der GitHub-Aktion um:
    1. Die aktuellen Branch-Daten zu verwenden, wenn sie bereits existieren. (z.B.: --if-branch "$GITHUB_REF_NAME")
    2. Erstellen Sie einen Klon der PR-Zielbranch-Daten und Schwellenwert, wenn sie bereits existieren. (z.B.: --else-if-branch "$GITHUB_BASE_REF")
    3. Ansonsten erstellen Sie einen Klon der main Branch-Daten und Schwellenwerte. (z.B.: --else-if-branch main)
    4. Es gibt mehrere Optionen für die Einstellung des Projektbranches. Siehe Branch Auswahl für einen vollständigen Überblick.
  3. Setzen Sie das GitHub API Authentifizierungstoken. (z.B.: --github-actions ${{ secrets.GITHUB_TOKEN }}) Wenn diese Option als Teil einer Pull-Anfrage gesetzt ist, werden die Ergebnisse als Kommentar zur Pull-Anfrage hinzugefügt. Dies verwendet die GitHub Actions GITHUB_TOKEN Umgebungsvariable.
  4. Siehe die bencher run Dokumentation für einen vollständigen Überblick über alle Möglichkeiten zur Konfiguration des Pull-Anfragen-Kommentars mit den --ci-* Flags.

Pull-Anfragen von Forks

Wenn Sie planen, Pull-Anfragen von Forks anzunehmen, wie es oft der Fall bei öffentlichen Open-Source-Projekten ist, müssen Sie die Dinge ein wenig anders behandeln. Aus Sicherheitsgründen stehen Geheimnisse wie Ihr BENCHER_API_TOKEN und das GITHUB_TOKEN nicht in GitHub-Aktionen für Fork-PRs zur Verfügung. Das heißt, wenn ein externer Beitragender einen PR von einem Fork eröffnet, wird das obige Beispiel nicht funktionieren. Es gibt drei Optionen für Fork-PRs:

Benchmark Fork-PR vom Zielbranch

on:
  push:
    branches: main
  pull_request_target:

jobs:
  benchmark_main_with_bencher:
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    name: Benchmark main with Bencher
    runs-on: ubuntu-latest
    env:
      BENCHER_PROJECT: save-walter-white
      BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }}
      BENCHER_TESTBED: ubuntu-latest
      BENCHER_ADAPTER: json
    steps:
      - uses: actions/checkout@v3
      - uses: bencherdev/bencher@main
      - name: Track Benchmarks with Bencher
        run: |
          bencher run \
          --branch main \
          --err \
          "bencher mock"

  benchmark_pr_with_bencher:
    if: github.event_name == 'pull_request_target'
    name: Benchmark PR with Bencher
    runs-on: ubuntu-latest
    env:
      BENCHER_PROJECT: save-walter-white
      BENCHER_ADAPTER: json
      BENCHER_TESTBED: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          ref: ${{ github.event.pull_request.head.sha }}
          repository: ${{ github.event.pull_request.head.repo.full_name }}
          persist-credentials: false
      - uses: bencherdev/bencher@main
      - name: Track Benchmarks with Bencher
        run: |
          bencher run \
          --if-branch "${{ github.event.pull_request.head.ref }}" \
          --else-if-branch "${{ github.event.pull_request.base.ref }}" \
          --else-if-branch main \
          --github-actions "${{ secrets.GITHUB_TOKEN }}" \
          --token "${{ secrets.BENCHER_API_TOKEN }}" \
          --err \
          "bencher mock"
  1. Lauf push Events zur main Zweig und zu pull_request_target Events.
  2. Erstellen Sie einen job der nur für push Events zum main Zweig läuft. Abgesehen von der if Bedingung ist dieser Job fast identisch mit dem ursprünglichen Beispiel oben.
  3. Erstellen Sie einen job der nur für pull_request_target Events läuft.
    1. Checkout des Pull-Anfrage-Zweigs.
    2. Übergeben Sie alle Geheimnisse direkt. Verwenden Sie --token ${{ secrets.BENCHER_API_TOKEN }} anstelle der BENCHER_API_TOKEN Umgebungsvariable.
    3. Führen Sie Ihre Pull-Anfrage-Benchmarks durch und verfolgen Sie diese mit bencher run.

Diese Einrichtung funktioniert, weil pull_request_target im Kontext des Zielzweigs der Pull-Anfrage läuft, wo Geheimnisse wie Ihr BENCHER_API_TOKEN und das GITHUB_TOKEN verfügbar sind. Daher wird dieser Workflow nur dann ausgeführt, wenn er auf dem Ziel Zweig existiert. Vermeiden Sie das Einstellen von Geheimnissen als Umgebungsvariablen, wie BENCHER_API_TOKEN. Übergeben Sie stattdessen das API-Token explizit an bencher run. (z.B.: --token ${{ secrets.BENCHER_API_TOKEN }}) Siehe diese GitHub Security Lab Aufschreibung und diesen Blogbeitrag zur Vermeidung von pwn-Anfragen für einen vollständigen Überblick.

Benchmark Fork-PR vom Zielbranch mit erforderlichen Prüfern

on:
  push:
    branches: main
  pull_request_target:

jobs:
  benchmark_main_with_bencher:
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    name: Benchmark main with Bencher
    runs-on: ubuntu-latest
    env:
      BENCHER_PROJECT: save-walter-white
      BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }}
      BENCHER_TESTBED: ubuntu-latest
      BENCHER_ADAPTER: json
    steps:
      - uses: actions/checkout@v3
      - uses: bencherdev/bencher@main
      - name: Track Benchmarks with Bencher
        run: |
          bencher run \
          --branch main \
          --err \
          "bencher mock"

  benchmark_pr_requires_review:
    if: github.event_name == 'pull_request_target'
    environment:
      ${{ (github.event.pull_request.head.repo.full_name == github.repository && 'internal') || 'external' }}
    runs-on: ubuntu-latest
    steps:
      - run: true

  benchmark_pr_with_bencher:
    needs: benchmark_pr_requires_review
    name: Benchmark PR with Bencher
    runs-on: ubuntu-latest
    env:
      BENCHER_PROJECT: save-walter-white
      BENCHER_ADAPTER: json
      BENCHER_TESTBED: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          ref: ${{ github.event.pull_request.head.sha }}
          repository: ${{ github.event.pull_request.head.repo.full_name }}
          persist-credentials: false
      - uses: bencherdev/bencher@main
      - name: Track Benchmarks with Bencher
        run: |
          bencher run \
          --if-branch "${{ github.event.pull_request.head.ref }}" \
          --else-if-branch "${{ github.event.pull_request.base.ref }}" \
          --else-if-branch main \
          --github-actions "${{ secrets.GITHUB_TOKEN }}" \
          --token "${{ secrets.BENCHER_API_TOKEN }}" \
          --err \
          "bencher mock"

Diese Einrichtung ist genau die gleiche wie Benchmark Fork-PR vom Zielbranch mit der zusätzlichen Anforderung der Genehmigung eines erforderlichen Prüfer vor jedem Lauf einer Fork-Pull-Anfrage. Pull-Anfragen aus demselben Repository benötigen keine Genehmigung. Um dies einzurichten, müssen Sie zwei GitHub Action-Umgebungen erstellen (z.B.: Repo -> Einstellungen -> Umgebungen -> Neue Umgebung). Die interne Umgebung sollte keine Schutzregeln für die Bereitstellung haben. Die externe Umgebung sollte jedoch Erforderliche Prüfer haben, die denen vertraut sind, die Fork PRs vor dem Benchmarking überprüfen.

Benchmark Fork PR und Hochladen vom Standard-Zweig

name: Run and Cache Benchmarks

on: pull_request

jobs:
  benchmark:
    name: Run Benchmarks
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Mock Benchmark
        run: echo '{"bencher::mock_0": { "latency": { "value": 1.0 }}}' &> benchmark_results.txt
      - uses: actions/upload-artifact@v3
        with:
          name: benchmark_results.txt
          path: ./benchmark_results.txt
      - uses: actions/upload-artifact@v3
        with:
          name: pr_event.json
          path: ${{ env.GITHUB_EVENT_PATH }}
name: Track Benchmarks

on:
  workflow_run:
    workflows: [Run and Cache Benchmarks]
    types:
      - completed

jobs:
  track_with_bencher:
    if: ${{ github.event.workflow_run.conclusion == 'success' }}
    runs-on: ubuntu-latest
    env:
      BENCHER_PROJECT: save-walter-white
      BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }}
      BENCHER_ADAPTER: json
      BENCHER_TESTBED: ubuntu-latest
      BENCHMARK_RESULTS: benchmark_results.txt
      PR_EVENT: pr_event.json
    steps:
      - name: Download Benchmark Results
        uses: actions/github-script@v6
        with:
          script: |
            function downloadArtifact(artifactName) {
              let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
                owner: context.repo.owner,
                repo: context.repo.repo,
                run_id: context.payload.workflow_run.id,
              });
              let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => {
                return artifact.name == artifactName
              })[0];
              if (!matchArtifact) {
                core.setFailed(`Failed to find artifact: ${artifactName}`);
              }
              let download = await github.rest.actions.downloadArtifact({
                owner: context.repo.owner,
                repo: context.repo.repo,
                artifact_id: matchArtifact.id,
                archive_format: 'zip',
              });
              let fs = require('fs');
              fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/${artifactName}.zip`, Buffer.from(download.data));
            }
            downloadArtifact(process.env.BENCHMARK_RESULTS);
            downloadArtifact(process.env.PR_EVENT);
      - name: Unzip Benchmark Results
        run: |
          unzip $BENCHMARK_RESULTS.zip
          unzip $PR_EVENT.zip
      - name: Export PR Context
        uses: actions/github-script@v6
        with:
          script: |
            let fs = require('fs');
            let prEvent = JSON.parse(fs.readFileSync(process.env.PR_EVENT, {encoding: 'utf8'}));
            fs.appendFileSync(process.env.GITHUB_ENV, `PR_NUMBER=${prEvent.number}`);
            fs.appendFileSync(process.env.GITHUB_ENV, `PR_HEAD=${prEvent.pull_request.head.ref}`);
            fs.appendFileSync(process.env.GITHUB_ENV, `PR_BASE=${prEvent.pull_request.base.ref}`);
      - uses: bencherdev/bencher@main
          - name: Track Benchmarks with Bencher
            run: |
              bencher run \
              --if-branch "${{ env.PR_HEAD }}" \
              --else-if-branch "${{ env.PR_BASE }}" \
              --else-if-branch main \
              --github-actions "${{ secrets.GITHUB_TOKEN }}" \
              --ci-number "${{ env.PR_NUMBER }}" \
              --err \
              --file $BENCHMARK_RESULTS
  1. Erstellen Sie eine Run and Cache Benchmarks Workflow-Datei.
  2. Führen Sie Ihre Benchmarks bei pull_request Events durch.
  3. Speichern Sie die Benchmark-Ergebnisse in einer Datei und laden Sie diese als Artefakt hoch.
  4. Laden Sie das pull_request Event als Artefakt hoch.
  5. Erstellen Sie eine zweite Workflow-Datei, Track Benchmarks.
  6. Verketten Sie Track Benchmarks mit Run and Cache Benchmarks mit dem Event workflow_run.
  7. Extrahieren Sie die notwendigen Daten aus dem gecachten pull_request Event.
  8. Verfolgen Sie die gecachten Benchmark-Ergebnisse mit bencher run.
  9. Erstellen Sie eine dritte Workflow-Datei und verwenden Sie das ursprüngliche obige Beispiel, um push Events zur main Zweig auszuführen.

Diese Einrichtung funktioniert, weil workflow_run im Kontext des Standardzweigs des Repositorys läuft, wo Geheimnisse wie Ihr BENCHER_API_TOKEN und das GITHUB_TOKEN verfügbar sind. Daher werden diese Workflows nur dann ausgeführt, wenn sie auf dem Standard Branch existieren. Siehe Verwendung von Daten aus dem auslösenden Workflow für einen vollständigen Überblick. Die Pull-Anfrage-Nummer, der Head-Zweig und der Base-Zweig, die im initialen Workflow verwendet wurden, müssen explizit übergeben werden, da sie innerhalb von workflow_run nicht verfügbar sind.



🐰 Herzlichen Glückwunsch! Sie haben gelernt, wie man Bencher in GitHub-Aktionen verwendet! 🎉


Weitermachen: Überblick über Benchmarking ➡

🤖 Dieses Dokument wurde automatisch von OpenAI GPT-4 generiert. Es ist möglicherweise nicht korrekt und kann Fehler enthalten. Wenn Sie Fehler finden, öffnen Sie bitte ein Problem auf GitHub.