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

Pull Requests

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

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

on:
pull_request:
types: [opened, reopened, synchronize]
jobs:
benchmark_pr_with_bencher:
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
permissions:
pull-requests: write
name: Continuous Benchmarking with Bencher
runs-on: ubuntu-latest
env:
BENCHER_PROJECT: save-walter-white
BENCHER_TESTBED: ubuntu-latest
BENCHER_ADAPTER: json
steps:
- uses: actions/checkout@v4
- 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 }}" \
--token "${{ secrets.BENCHER_API_TOKEN }}" \
--err \
"bencher mock"
  1. Создайте файл workflow для GitHub Actions (например: .github/workflows/pr_benchmarks.yml)
  2. Запускайте при событиях pull_request только и только если запрос на вытягивание происходит из того же репозитория. Для обработки PR из форков см. Запросы на вытягивание из форков ниже.
  3. Установите разрешения для GITHUB_TOKEN на write для pull-requests. В зависимости от ваших настроек GitHub, это может быть не требуется. Но для всех организаций и персональных репозиториев созданных после 02 февраля 2023 года, это становится поведением по умолчанию. См. документацию GitHub для полного обзора.
  4. Выберите ветку для использования:
    1. Используйте текущие данные ветки, если они уже существуют. (например: --if-branch "$GITHUB_REF_NAME")
    2. Создайте клон данных целевой ветки PR и порогов, если они уже существуют. (например: --else-if-branch "$GITHUB_BASE_REF")
    3. В противном случае создайте клон данных основной ветки (main) и порогов. (например: --else-if-branch main)
  5. Установите токен аутентификации API GitHub. (например: --github-actions "${{ secrets.GITHUB_TOKEN }}") Когда этот параметр установлен в рамках запроса на вытягивание, то результаты будут добавлены к запросу на вытягивание в виде комментария. Использует переменную среды GITHUB_TOKEN от GitHub Actions.
  6. Посмотрите в документации bencher run полное описание всех способов настройки комментария запроса на вытягивание с --ci-* флагами.
  7. (Не показано) Создайте второй файл workflow для GitHub Actions и используйте приведенный выше пример для запуска по событиям push в основную ветку (main). (например: .github/workflows/benchmarks.yml)

Pull Requests из Forks

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

Бенчмарк целевой ветки PR из форка с требуемыми рецензентами

⚠️ Это очень, очень важно тщательно проверять все PR из форков перед утверждением! В противном случае это может привести к запросу на pwn!

Если вы предпочли бы избежать этого, см. раздел Benchmark Fork PR и загрузка из ветки по умолчанию ниже.

on:
pull_request_target:
types: [opened, reopened, synchronize]
jobs:
fork_pr_requires_review:
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: fork_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@v4
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.number }}/merge' \
--else-if-branch '${{ github.base_ref }}' \
--else-if-branch main \
--github-actions "${{ secrets.GITHUB_TOKEN }}" \
--token "${{ secrets.BENCHER_API_TOKEN }}" \
--err \
"bencher mock"
  1. Создайте файл workflow для GitHub Actions. (например: .github/workflows/pr_benchmarks.yml)
  2. Запустите события pull_request_target.
  3. Создайте job с именем fork_pr_requires_review, которая требует утверждения от обязательного рецензента перед каждым запуском коммита во внешнем pull request (external).
  4. Создайте третий job, который зависит от fork_pr_requires_review.
    1. Выполните checkout ветки пулл-реквеста, но не сохраняйте учетные данные git. (например: persist-credentials: false)
    2. Используйте одинарные кавычки для всех ненадежных входных данных. (например: --if-branch '${{ github.head_ref }}')
    3. Передавайте все секреты напрямую. (например: --token "${{ secrets.BENCHER_API_TOKEN }}")
    4. Запустите и отслеживайте ваши пулл-реквесты с помощью bencher run.
  5. (Не показано) Создайте второй файл workflow для GitHub Actions и используйте изначальный приведенный выше пример для запуска на событиях push к ветке main. (например: .github/workflows/benchmarks.yml)

Этот сценарий работает, потому что pull_request_target выполняется в контексте целевой ветки запроса на вытягивание, где доступны секреты, такие как BENCHER_API_TOKEN и GITHUB_TOKEN. Поэтому, этот рабочий процесс будет выполняться только если он присутствует на целевой ветке.

Для настройки этого вам нужно создать две среды GitHub Action (например: Repo -> Settings -> Environments -> New environment). Среда internal не должна иметь Deployment protection rules. Однако, среда external должна иметь установленные Required reviewers среди тех, кто доверен для просмотра fork PRs перед бенчмаркингом.

Очень важно обернуть имя ветки PR (head ref) в одинарные кавычки. (например, --if-branch '${{ github.head_ref }}'). В противном случае злоумышленник может создать вредоносно названную ветку, которая будет выполнять внедрение команды. См. Этот раздел GitHub Security Lab о том, как предотвращать pwn запросы от ненадежного входного сигнала.

Избегайте установки любых секретов в качестве переменных среды, таких как GITHUB_TOKEN и BENCHER_API_TOKEN. Вместо этого явно передавайте секреты в bencher run. (например, --token "${{ secrets.BENCHER_API_TOKEN }}") См. Этот раздел GitHub Security Lab и этот блог-пост на тему предотвращения pwn запросов для полного обзора.

Бенчмарк PR из форка и загрузка из основной ветки

name: Run and Cache Benchmarks
on:
pull_request:
types: [opened, reopened, synchronize]
jobs:
benchmark:
name: Run Benchmarks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Mock Benchmarking
run: |
/bin/echo '{ "bencher::mock_0": { "latency": { "value": 1.0 } } }' > benchmark_results.json
- name: Upload Benchmark Results
uses: actions/upload-artifact@v4
with:
name: benchmark_results.json
path: ./benchmark_results.json
- name: Upload GitHub Pull Request Event
uses: actions/upload-artifact@v4
with:
name: event.json
path: ${{ github.event_path }}
  1. Создайте файл рабочего процесса Run and Cache Benchmarks. (например: .github/workflows/pr_benchmarks.yml)
  2. Запустите все задания в рабочем процессе при событиях pull_request.
  3. Запустите бенчмарки и сохраните результаты в файл. (например: benchmark_results.json)
  4. Загрузите файл с результатами теста как артефакт.
  5. Загрузите объект события pull_request как артефакт.
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_ADAPTER: json
BENCHER_TESTBED: ubuntu-latest
BENCHMARK_RESULTS: benchmark_results.json
PR_EVENT: event.json
steps:
- name: Download Benchmark Results
uses: actions/github-script@v6
with:
script: |
async 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));
}
await downloadArtifact(process.env.BENCHMARK_RESULTS);
await downloadArtifact(process.env.PR_EVENT);
- name: Unzip Benchmark Results
run: |
unzip $BENCHMARK_RESULTS.zip
unzip $PR_EVENT.zip
- name: Export PR Event Data
uses: actions/github-script@v6
with:
script: |
let fs = require('fs');
let prEvent = JSON.parse(fs.readFileSync(process.env.PR_EVENT, {encoding: 'utf8'}));
core.exportVariable("PR_HEAD", `${prEvent.number}/merge`);
core.exportVariable("PR_BASE", prEvent.pull_request.base.ref);
core.exportVariable("PR_DEFAULT", prEvent.pull_request.base.repo.default_branch);
core.exportVariable("PR_NUMBER", prEvent.number);
- 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 '${{ env.PR_DEFAULT }}' \
--ci-number '${{ env.PR_NUMBER }}' \
--github-actions "${{ secrets.GITHUB_TOKEN }}" \
--token "${{ secrets.BENCHER_API_TOKEN }}" \
--err \
--file "$BENCHMARK_RESULTS"
  1. Создайте второй файл рабочего процесса, Track Benchmarks. (например: .github/workflows/track_benchmarks.yml)
  2. Соедините Track Benchmarks с Run and Cache Benchmarks с использованием события workflow_run.
  3. Скачайте кэшированные результаты бенчмарка и объект pull_request.
  4. Извлеките кэшированные результаты бенчмарка и объект pull_request.
  5. Экспортируйте необходимые данные из объекта pull_request в переменные окружения.
  6. Отследите кэшированные результаты бенчмарка с помощью bencher run:
    1. Используйте одинарные кавычки для всех ненадежных входных данных. (например: --if-branch '${{ env.PR_HEAD }}')
    2. Явно передайте номер запроса. (например: --ci-number '${{ env.PR_NUMBER }}')
    3. Передайте путь к файлу с результатами бенчмарка. (например: --file "$BENCHMARK_RESULTS")
  7. (Не показано) Создайте третий файл GitHub Actions workflow и используйте изначальный приведенный выше пример для запуска на событиях push к ветке main. (например: .github/workflows/benchmarks.yml)

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

Очень важно обернуть имя ветки PR (head ref) в одинарные кавычки. (например, --if-branch '${{ env.PR_HEAD }}'). В противном случае злоумышленник может создать вредоносно названную ветку, которая выполнит внедрение команды. См. Этот раздел GitHub Security Lab для полного обзора.

Избегайте установки любых секретов в качестве переменных среды в файле рабочего процесса Run and Cache Benchmarks. См. этот GitHub Security Lab и этот блог-пост на тему предотвращения pwn запросов для полного обзора.



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


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

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