Как использовать Bencher в GitHub Actions


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. Создайте файл workflow для GitHub Actions. (пример: .github/workflows/benchmark.yml)
  2. Запускайте при событиях push в main ветку. Подробнее см. в документации GitHub Actions on и ниже в разделе Pull Requests.
  3. Создайте job для GitHub Actions. (пример: benchmark_with_bencher)
  4. Проект уже должен существовать. Установите флаг --project или переменную среды BENCHER_PROJECT на символическое имя или UUID проекта (пример: BENCHER_PROJECT: save-walter-white).
  5. API токен уже должен существовать. Добавьте BENCHER_API_TOKEN как секрет репозитория. (пример: Repo -> Settings -> Secrets and variables -> Actions -> New repository secret) Установите флаг --token или переменную среды BENCHER_API_TOKEN на API токен. (пример: BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }})
  6. Необязательный шаг: установите флаг --testbed или переменную среды BENCHER_TESTBED на символическое имя или UUID Testbed. (пример: BENCHER_TESTBED: ubuntu-latest) Testbed должен уже существовать. Если это не задано, то будет использоваться Testbed localhost.
  7. Необязательный шаг: установите флаг --adapter или переменную среды BENCHER_ADAPTER на желаемое имя адаптера. (пример: BENCHER_ADAPTER: json) Если это не задано, то будет использоваться адаптер magic. Подробнее см. адаптеры для benchmark harness.
  8. Произведите клонирование вашего исходниго кода. (пример: uses: actions/checkout@v3)
  9. Установите Bencher CLI используя GitHub Action. (пример: uses: bencherdev/bencher@main)
  10. Отслеживайте свои бенчмарки с помощью подкоманды CLI bencher run:
    1. Необязательный шаг: установите флаг --branch или переменную среды BENCHER_BRANCH на символическое имя или UUID ветки. (пример: --branch main) Ветвь должна уже существовать. Если это не задано, то используется ветвь main.
    2. Установите команду, чтобы она завершилась с ошибкой, если создано предупреждение. (пример: --err) Чтобы предупреждение было создано, требуется уже существующий порог.
    3. Запустите бенчмарки и сгенерируйте отчет из результатов. (пример: "bencher mock")

Pull Requests

Чтобы отследить регрессию производительности в Pull Requests, вам потребуется запустить ваши бенчмарки на PRs. Если вы ожидаете PRs только из ветвей в рамках одного и того же репозитория, вы можете просто модифицировать пример выше, чтобы также запускать его on pull_request событиях.

⚠️ Это решение работает, только если все PRs из одного и того же репозитория! См. ниже Pull Requests from Forks.

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. Запускайте при событиях push в main ветку и на pull_request событиях. Важно ограничить запуск при событии push только для выбранных ветвей (например, main), чтобы предотвратить двойной запуск при пушах в ветки PR!
  2. Вместо всегда использования ветки main, используйте переменные среды по умолчанию GitHub Action для:
    1. Использование текущих данных ветки, если они уже существуют. (пример: --if-branch "$GITHUB_REF_NAME")
    2. Создания клонов данных целевой ветки PR и порогов, если они уже существуют. (пример: --else-if-branch "$GITHUB_BASE_REF")
    3. В других случаях создания клонов данных ветки main и порогов. (пример: --else-if-branch main)
    4. Есть несколько вариантов установки ветки проекта. Подробнее см. выбор ветви.
  3. Установите токен аутентификации на GitHub API. (пример: --github-actions ${{ secrets.GITHUB_TOKEN }}) При установке этой опции как часть pull request, результаты будут добавлены в pull request как комментарий. Используется переменная среды GITHUB_TOKEN в GitHub Actions.
  4. См. документацию bencher run для подробного обзора всех способов настройки комментария к pull request с помощью флагов --ci-*.

Pull Requests из форков

Если вы планируете принимать pull requests от форков, как это часто бывает в открытых проектах с открытым исходным кодом, то вам придется немного иначе обрабатывать такие ситуации. По соображениям безопасности, секреты типа вашего BENCHER_API_TOKEN и GITHUB_TOKEN недоступны в GitHub Actions для PR из форков. То есть, если внешний участник открывает PR из форка, пример выше не будет работать. Есть три варианта для PR из форков:

Benchmark Fork PR из целевой ветки

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. Запускайте на событиях push в main ветку и на событиях pull_request_target.
  2. Создайте job который запускается только для событий push в main ветку. За исключением условия if, этот job почти идентичен оригинальному примеру выше.
  3. Создайте job который запускается только для событий pull_request_target.
    1. Произведите клонирование ветки pull request.
    2. Передайте все секреты непосредственно. Используйте --token ${{ secrets.BENCHER_API_TOKEN }} вместо переменной среды BENCHER_API_TOKEN.
    3. Запустите бенчмарки вашего pull request и отслеживайте их с bencher run.

Эта установка работает, потому что pull_request_target выполняется в контексте целевой ветки pull request, где доступны секреты, такие как ваш BENCHER_API_TOKEN и GITHUB_TOKEN. Поэтому, этот workflow будет запущен только если он существует на целевой ветке. Избегайте установки любых секретов в переменных среды, таких как BENCHER_API_TOKEN. Вместо этого явно передавайте API токен в bencher run. (пример: --token ${{ secrets.BENCHER_API_TOKEN }}) Смотрите GitHub Security Lab write up и эту статью в блоге о предотвращении запросов вредоносного контента для подробного обзора.

Benchmark Fork PR из целевой ветки с обязательными ревьюерами

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"

Эта установка точно такая же, как и Benchmark Fork PR из целевой ветки с дополнительным требованием одобрения от Обязательного Ревьюера перед каждым запуском бенчмарка для pull request из форка. Pull requests из того же репозитория не требуют одобрения. Для настройки этого вам нужно создать два окружения GitHub Action (пример: Repo -> Settings -> Environments -> New environment). Окружение internal не должно иметь Deployment protection rules. Однако, окружение external должно иметь установленными Required reviewers тех, кто доверен для просмотра PR из форка перед бенчмаркингом.

Benchmark Fork PR и загрузка из ветки по умолчанию

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. Создайте файл workflow Run and Cache Benchmarks.
  2. Запустите ваши бенчмарки на событиях pull_request.
  3. Сохраните результаты бенчмарков в файл и загрузите их как артефакт.
  4. Загрузите событие pull_request как артефакт.
  5. Создайте второй файл workflow, Track Benchmarks.
  6. Свяжите Track Benchmarks с Run and Cache Benchmarks по событию workflow_run.
  7. Извлеките необходимые данные из закешированного события pull_request.
  8. Отследите закешированные результаты бенчмарков с bencher run.
  9. Создайте третий файл workflow и используйте оригинальный пример выше для запуска на событиях push в main ветку.

Эта установка работает, потому что workflow_run выполняется в контексте ветки по умолчанию репозитория, где доступны секреты, такие как ваш BENCHER_API_TOKEN и GITHUB_TOKEN. Поэтому, эти workflow будут запущены только если они существуют на ветке по умолчанию. Смотрите использование данных от запускающего workflow для подробного обзора. Номер pull request, ветка шапки и основная ветка, использованные в исходном workflow, должны быть явно переданы, так как они недоступны внутри workflow_run.



🐰 Поздравляем! Вы научились использовать Bencher в GitHub Actions! 🎉


Продолжите: Обзор бенчмаркинга ➡

🤖 Этот документ был автоматически создан OpenAI GPT-4. Оно может быть неточным и содержать ошибки. Если вы обнаружите какие-либо ошибки, откройте проблему на GitHub.