GitHub Actions에서 Bencher 사용하는 방법


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. GitHub Actions workflow 파일을 생성합니다. (예: .github/workflows/benchmark.yml)
  2. push 이벤트를 main 브랜치로 실행합니다. 전체 개요는 GitHub Actions on 문서를 참조하세요. 또한 아래의 Pull Requests도 참조하세요.
  3. GitHub Actions job를 생성합니다. (예: benchmark_with_bencher)
  4. 프로젝트는 이미 존재해야 합니다. --project 플래그를 설정하거나 BENCHER_PROJECT 환경 변수를 프로젝트 슬러그나 UUID로 설정합니다. (예: BENCHER_PROJECT: save-walter-white).
  5. API 토큰은 이미 존재해야 합니다. BENCHER_API_TOKEN레포지토리 시크릿으로 추가합니다. (예: 저장소 -> 설정 -> 시크릿 및 변수 -> 작업 -> 새 레포지토리 시크릿) --token 플래그를 설정하거나 BENCHER_API_TOKEN 환경 변수를 API 토큰으로 설정합니다. (예: BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }})
  6. 선택 사항: --testbed 플래그를 설정하거나 BENCHER_TESTBED 환경 변수를 테스트 베드 슬러그나 UUID로 설정합니다. (예: BENCHER_TESTBED: ubuntu-latest) 테스트 베드는 반드시 이미 존재해야 합니다. 만약 이것을 설정하지 않으면, localhost 테스트 베드가 사용되게 됩니다.
  7. 선택 사항: --adapter 플래그를 설정하거나 BENCHER_ADAPTER 환경 변수를 원하는 어댑터 이름으로 설정합니다. (예: BENCHER_ADAPTER: json) 만약 이것을 설정하지 않으면, magic 어댑터가 사용되게 됩니다. 전체 개요는 벤치마크 하네스 어댑터를 참조하세요.
  8. 소스 코드를 체크아웃합니다. (예: uses: actions/checkout@v3)
  9. GitHub Action을 사용하여 Bencher CLI를 설치합니다. (예: uses: bencherdev/bencher@main)
  10. bencher run CLI 하위 명령을 사용하여 벤치마크를 추적합니다:
    1. 선택 사항: --branch 플래그를 설정하거나 BENCHER_BRANCH 환경 변수를 브랜치 슬러그나 UUID로 설정합니다. (예: --branch main) 브랜치는 반드시 이미 존재해야 합니다. 만약 이것을 설정하지 않으면, main 브랜치가 사용되게 됩니다.
    2. 경고가 생성되면 명령이 실패하도록 설정합니다. (예: --err) 경고가 생성되기 위해서는, 임계값이 이미 존재해야 합니다.
    3. 벤치마크를 실행하고 결과에서 보고서를 생성합니다. (예: "bencher mock")

Pull Requests

Pull Request에서 성능 회귀를 잡아내기 위해 PR에서 벤치마크를 실행해야 합니다. 당신이 같은 저장소 내의 브랜치로부터 PR만 받을 것이라고 예상한다면, 위의 예제를 수정해서 on pull_request 이벤트에서도 실행하게 하십시오.

⚠️ 이 해결책은 모든 PR들이 같은 저장소에서 오는 경우에만 작동합니다! 아래의 Fork들로부터의 Pull Requests를 참조하세요.

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 이벤트에서도 실행합니다. PR 브랜치에 대한 push가 두 번 실행되는 것을 막기 위해, push를 선택된 브랜치(예: main)로 실행하는 것이 중요합니다!
  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 Actions GITHUB_TOKEN 환경 변수를 사용합니다.
  4. --ci-* 플래그로 pull request 댓글을 설정하는 모든 방법에 대한 전체 개요는 bencher run 문서를 참조하세요.

Fork들로부터의 Pull Requests

당신이 공개 오픈 소스 프로젝트에서 종종 하는 경우처럼 fork들로부터 pull request를 받을 계획이라면, 소소하게 다른 방식으로 처리해야 합니다. 보안 문제로 인해, BENCHER_API_TOKENGITHUB_TOKEN과 같은 비밀 정보는 fork PRs에서의 GitHub Actions을 사용할 수 없습니다. 즉, 외부 기여자가 fork에서 PR을 열면 위의 예시는 작동하지 않게 됩니다. fork PRs에는 세 가지 옵션이 있습니다:

Target Branch로부터 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 브랜치로 실행하고 on pull_request_target events를 실행합니다.
  2. push 이벤트를 main 브랜치로만 실행하는 job을 생성합니다. if 조건을 제외하고, 이 job은 원래의 예제와 거의 동일합니다.
  3. pull_request_target 이벤트를 실행하는 job을 생성합니다.
    1. pull request 브랜치를 체크아웃합니다.
    2. 모든 비밀 정보를 직접 전달합니다. BENCHER_API_TOKEN 환경 변수 대신 --token ${{ secrets.BENCHER_API_TOKEN }}을 사용합니다.
    3. bencher run을 사용하여 pull request의 벤치마크를 실행하고 추적합니다.

이 설정이 작동하는 이유는 pull_request_target이 pull request의 대상 브랜치로 실행되는 컨텍스트 내에서 실행되기 때문이며, 이곳에서는 BENCHER_API_TOKENGITHUB_TOKEN과 같은 비밀 정보가 사용 가능합니다. 따라서, 이 워크플로우는 target 브랜치에 존재하는 경우에만 실행됩니다. BENCHER_API_TOKEN과 같은 비밀 정보를 환경 변수로 설정하지 마십시오. 대신 명시적으로 API 토큰을 bencher run에 전달하십시오. (예: --token ${{ secrets.BENCHER_API_TOKEN }}) 전체 개요는 GitHub Security Lab 글이 블로그 게시물 에서 pwn 요청을 방지하는 방법을 확인할 수 있습니다.

필수 리뷰어가 있는 Target Branch로부터 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"

이 설정은 Target Branch로부터 Fork PR를 벤치마크 와 완전히 동일하지만, 각 fork pull request 실행 전에 필수 리뷰어의 승인이 필요로 하는 추가 요건이 있습니다. 같은 저장소에서 온 pull request는 승인이 필요하지 않습니다. 이를 설정하려면, 두 개의 GitHub Action 환경을 생성 해야 합니다 (예: 저장소 -> 설정 -> 환경 -> 새로운 환경). internal 환경에는 Deploy protection rules가 없어야 합니다. 그러나 external 환경에는 벤치마킹 전에 fork PRs를 검토할 수 있는 사람들이 필수 리뷰어로 설정되어야 합니다.

기본 Branch로부터 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. Run and Cache Benchmarks 워크플로우 파일을 생성합니다.
  2. 벤치마크를 pull_request 이벤트에서 실행합니다.
  3. 벤치마크 결과를 파일에 저장하고 이를 아티팩트로 업로드합니다.
  4. pull_request 이벤트를 아티팩트로 업로드합니다.
  5. 두 번째 워크플로우 파일인 Track Benchmarks를 생성합니다.
  6. workflow_run 이벤트를 사용하여 Track BenchmarksRun and Cache Benchmarks에 연결합니다.
  7. 캐시된 pull_request 이벤트에서 필요한 데이터를 추출합니다.
  8. 캐시된 벤치마크 결과를 bencher run으로 추적합니다.
  9. push 이벤트를 main 브랜치로 실행하는 초기 예를 사용하여 세 번째 워크플로우 파일을 생성합니다.

이 설정은 workflow_run이 레포지토리의 기본 브랜치 컨텍스트 내에서 실행되므로 작동합니다. 따라서, BENCHER_API_TOKENGITHUB_TOKEN과 같은 비밀 정보가 사용 가능합니다. 따라서, 이 워크플로우는 default 브랜치에 존재하는 경우에만 실행됩니다. 전체 개요는 트리거 워크플로우에서 데이터 사용하기를 참조할 수 있습니다. 초기 워크플로우에서 사용된 pull request 번호, 헤드 브랜치, 및 기본 브랜치는 workflow_run내에서는 사용할 수 없으므로 명시적으로 전달해야 합니다.



🐰 축하합니다! GitHub Actions에서 Bencher를 어떻게 사용하는지 배웠습니다! 🎉


계속 진행하세요: 벤치마킹 개요 ➡

🤖 이 문서는 OpenAI GPT-4에 의해 자동으로 생성되었습니다. 정확하지 않을 수도 있고 오류가 있을 수도 있습니다. 오류를 발견하면 GitHub에서 문제를 열어주세요.