|
| 1 | +name: 'Benchmarkoor' |
| 2 | +description: 'Run Ethereum execution client benchmarks using benchmarkoor' |
| 3 | +author: 'ethpandaops' |
| 4 | +branding: |
| 5 | + icon: 'activity' |
| 6 | + color: 'gray-dark' |
| 7 | + |
| 8 | +inputs: |
| 9 | + github-token: |
| 10 | + description: 'GitHub token for API access' |
| 11 | + required: true |
| 12 | + |
| 13 | + image: |
| 14 | + description: 'Docker image for benchmarkoor (e.g., ghcr.io/ethpandaops/benchmarkoor:master). If not provided, will build locally.' |
| 15 | + required: false |
| 16 | + default: '' |
| 17 | + |
| 18 | + git-ref: |
| 19 | + description: 'Git branch or commit hash to build from. Only used when image is not provided. Defaults to master.' |
| 20 | + required: false |
| 21 | + default: '' |
| 22 | + |
| 23 | + upload-artifacts: |
| 24 | + description: 'Whether to upload run results as GitHub artifacts' |
| 25 | + required: false |
| 26 | + default: 'false' |
| 27 | + |
| 28 | + run-config-url: |
| 29 | + description: 'URL for config file to download and pass via --config' |
| 30 | + required: false |
| 31 | + default: '' |
| 32 | + |
| 33 | + run-config: |
| 34 | + description: 'Raw YAML config content to pass via --config (appended after URL config)' |
| 35 | + required: false |
| 36 | + default: '' |
| 37 | + |
| 38 | + run-args: |
| 39 | + description: 'Extra flags passed to benchmarkoor run command' |
| 40 | + required: false |
| 41 | + default: '' |
| 42 | + |
| 43 | +runs: |
| 44 | + using: 'composite' |
| 45 | + steps: |
| 46 | + - name: Build Docker image locally |
| 47 | + if: inputs.image == '' |
| 48 | + shell: bash |
| 49 | + run: | |
| 50 | + GIT_REF="${{ inputs.git-ref }}" |
| 51 | + if [ -z "$GIT_REF" ]; then |
| 52 | + GIT_REF="master" |
| 53 | + fi |
| 54 | +
|
| 55 | + echo "Cloning https://github.com/ethpandaops/benchmarkoor.git at ref $GIT_REF" |
| 56 | + git clone https://github.com/ethpandaops/benchmarkoor.git benchmarkoor-build |
| 57 | + cd benchmarkoor-build |
| 58 | + git checkout "$GIT_REF" |
| 59 | +
|
| 60 | + echo "Building Docker image..." |
| 61 | + docker build -t benchmarkoor:local . |
| 62 | + cd .. |
| 63 | +
|
| 64 | + rm -rf benchmarkoor-build |
| 65 | +
|
| 66 | + - name: Determine which image to use |
| 67 | + id: determine-image |
| 68 | + shell: bash |
| 69 | + run: | |
| 70 | + if [ -n "${{ inputs.image }}" ]; then |
| 71 | + IMAGE="${{ inputs.image }}" |
| 72 | + echo "Using provided Docker image: ${IMAGE}" |
| 73 | + else |
| 74 | + IMAGE="benchmarkoor:local" |
| 75 | + echo "Using locally built image: ${IMAGE}" |
| 76 | + fi |
| 77 | + echo "image=${IMAGE}" >> $GITHUB_OUTPUT |
| 78 | +
|
| 79 | + if [ -z "$IMAGE" ]; then |
| 80 | + echo "ERROR: Docker image not specified" |
| 81 | + exit 1 |
| 82 | + fi |
| 83 | +
|
| 84 | + if [ "$IMAGE" != "benchmarkoor:local" ]; then |
| 85 | + echo "Pulling Docker image: ${IMAGE}" |
| 86 | + docker pull "${IMAGE}" || { |
| 87 | + echo "Failed to pull Docker image: ${IMAGE}" |
| 88 | + exit 1 |
| 89 | + } |
| 90 | + fi |
| 91 | +
|
| 92 | + - name: Get Job ID from GH API |
| 93 | + id: get-job-id |
| 94 | + shell: bash |
| 95 | + env: |
| 96 | + GH_TOKEN: ${{ inputs.github-token }} |
| 97 | + run: | |
| 98 | + jobs=$(gh api -F per_page=100 -X GET repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/attempts/${{ github.run_attempt }}/jobs) |
| 99 | + job_id=$(echo "$jobs" | jq -r '.jobs[] | select(.runner_name=="${{ runner.name }}" and .status=="in_progress") | .id') |
| 100 | + echo "job_id=${job_id}" >> "$GITHUB_OUTPUT" |
| 101 | +
|
| 102 | + - name: Run Benchmarkoor |
| 103 | + id: run-benchmarkoor |
| 104 | + shell: bash |
| 105 | + env: |
| 106 | + INPUT_RUN_CONFIG: ${{ inputs.run-config }} |
| 107 | + INPUT_RUN_CONFIG_URL: ${{ inputs.run-config-url }} |
| 108 | + run: | |
| 109 | + # Remove any leftover containers from a previous run |
| 110 | + docker rm -f benchmarkoor-run 2>/dev/null || true |
| 111 | + docker rm -f benchmarkoor-md 2>/dev/null || true |
| 112 | +
|
| 113 | + mkdir -p ${{ runner.temp }}/results |
| 114 | +
|
| 115 | + IMAGE="${{ steps.determine-image.outputs.image }}" |
| 116 | + echo "Running benchmarkoor with Docker image: ${IMAGE}" |
| 117 | +
|
| 118 | + # Download URL config if provided |
| 119 | + if [ -n "$INPUT_RUN_CONFIG_URL" ]; then |
| 120 | + echo "Downloading config from ${INPUT_RUN_CONFIG_URL}" |
| 121 | + curl -fsSL "${INPUT_RUN_CONFIG_URL}" -o "${{ runner.temp }}/benchmarkoor-config-url.yaml" |
| 122 | + fi |
| 123 | +
|
| 124 | + # Write inline config if provided |
| 125 | + if [ -n "$INPUT_RUN_CONFIG" ]; then |
| 126 | + cat <<'CONFIGEOF' > "${{ runner.temp }}/benchmarkoor-config-inline.yaml" |
| 127 | + ${{ inputs.run-config }} |
| 128 | + CONFIGEOF |
| 129 | + fi |
| 130 | +
|
| 131 | + # Build docker run command |
| 132 | + DOCKER_CMD="docker run --network=host --rm --name=benchmarkoor-run" |
| 133 | + DOCKER_CMD="$DOCKER_CMD -v /var/run/docker.sock:/var/run/docker.sock" |
| 134 | + DOCKER_CMD="$DOCKER_CMD -v ${{ runner.temp }}/results:/app/results" |
| 135 | + DOCKER_CMD="$DOCKER_CMD -v ${{ runner.temp }}:/app/configs" |
| 136 | + DOCKER_CMD="$DOCKER_CMD -v /tmp:/tmp" |
| 137 | + DOCKER_CMD="$DOCKER_CMD --cap-add=SYS_ADMIN" |
| 138 | + DOCKER_CMD="$DOCKER_CMD -v /proc/sys/vm/drop_caches:/host_drop_caches" |
| 139 | + DOCKER_CMD="$DOCKER_CMD -v /sys/devices/system/cpu:/host_sys_cpu" |
| 140 | + DOCKER_CMD="$DOCKER_CMD -e BENCHMARKOOR_GLOBAL_DROP_CACHES_PATH=/host_drop_caches" |
| 141 | + DOCKER_CMD="$DOCKER_CMD -e BENCHMARKOOR_GLOBAL_CPU_SYSFS_PATH=/host_sys_cpu" |
| 142 | + DOCKER_CMD="$DOCKER_CMD -e BENCHMARKOOR_BENCHMARK_RESULTS_DIR=/app/results" |
| 143 | + DOCKER_CMD="$DOCKER_CMD -e BENCHMARKOOR_BENCHMARK_RESULTS_OWNER=$(id -u):$(id -g)" |
| 144 | + DOCKER_CMD="$DOCKER_CMD ${IMAGE}" |
| 145 | + DOCKER_CMD="$DOCKER_CMD run" |
| 146 | +
|
| 147 | + # Add config files in order: URL config, inline config, override config (last wins) |
| 148 | + if [ -f "${{ runner.temp }}/benchmarkoor-config-url.yaml" ]; then |
| 149 | + DOCKER_CMD="$DOCKER_CMD --config=/app/configs/benchmarkoor-config-url.yaml" |
| 150 | + fi |
| 151 | +
|
| 152 | + if [ -f "${{ runner.temp }}/benchmarkoor-config-inline.yaml" ]; then |
| 153 | + DOCKER_CMD="$DOCKER_CMD --config=/app/configs/benchmarkoor-config-inline.yaml" |
| 154 | + fi |
| 155 | +
|
| 156 | + # Add GitHub Actions context as metadata labels |
| 157 | + DOCKER_CMD="$DOCKER_CMD --metadata.label=github.run_id=${{ github.run_id }}" |
| 158 | + DOCKER_CMD="$DOCKER_CMD --metadata.label=github.run_number=${{ github.run_number }}" |
| 159 | + DOCKER_CMD="$DOCKER_CMD --metadata.label=github.job=${{ github.job }}" |
| 160 | + DOCKER_CMD="$DOCKER_CMD --metadata.label=github.job_id=${{ steps.get-job-id.outputs.job_id }}" |
| 161 | + DOCKER_CMD="$DOCKER_CMD --metadata.label=github.repository=${{ github.repository }}" |
| 162 | + DOCKER_CMD="$DOCKER_CMD --metadata.label=github.workflow=\"${{ github.workflow }}\"" |
| 163 | + DOCKER_CMD="$DOCKER_CMD --metadata.label=github.sha=${{ github.sha }}" |
| 164 | + DOCKER_CMD="$DOCKER_CMD --metadata.label=github.actor=${{ github.actor }}" |
| 165 | + DOCKER_CMD="$DOCKER_CMD --metadata.label=github.event_name=${{ github.event_name }}" |
| 166 | + DOCKER_CMD="$DOCKER_CMD --metadata.label=github.ref=${{ github.ref }}" |
| 167 | +
|
| 168 | + # Append extra run args if provided |
| 169 | + if [ -n "${{ inputs.run-args }}" ]; then |
| 170 | + DOCKER_CMD="$DOCKER_CMD ${{ inputs.run-args }}" |
| 171 | + fi |
| 172 | +
|
| 173 | + # Execute the command |
| 174 | + echo "Running: $DOCKER_CMD" |
| 175 | + set +e |
| 176 | + eval $DOCKER_CMD & |
| 177 | + wait $! |
| 178 | + DOCKER_EXIT_CODE=$? |
| 179 | + set -e |
| 180 | +
|
| 181 | + # Find run directories |
| 182 | + RUN_DIRS="" |
| 183 | + if [ -d "${{ runner.temp }}/results/runs" ]; then |
| 184 | + RUN_DIRS=$(find "${{ runner.temp }}/results/runs" -mindepth 1 -maxdepth 1 -type d | sort | tr '\n' ' ') |
| 185 | + fi |
| 186 | +
|
| 187 | + echo "run-dirs=${RUN_DIRS}" >> $GITHUB_OUTPUT |
| 188 | +
|
| 189 | + if [ $DOCKER_EXIT_CODE -ne 0 ]; then |
| 190 | + echo "Benchmarkoor failed with exit code $DOCKER_EXIT_CODE" |
| 191 | + exit $DOCKER_EXIT_CODE |
| 192 | + fi |
| 193 | +
|
| 194 | + echo "Benchmarkoor completed successfully" |
| 195 | +
|
| 196 | + - name: Generate markdown summaries |
| 197 | + if: always() && steps.run-benchmarkoor.outputs.run-dirs != '' |
| 198 | + shell: bash |
| 199 | + run: | |
| 200 | + IMAGE="${{ steps.determine-image.outputs.image }}" |
| 201 | +
|
| 202 | + for RUN_DIR_HOST in ${{ steps.run-benchmarkoor.outputs.run-dirs }}; do |
| 203 | + RUN_DIR_NAME=$(basename "$RUN_DIR_HOST") |
| 204 | + CONTAINER_RUN_DIR="/app/results/runs/${RUN_DIR_NAME}" |
| 205 | +
|
| 206 | + echo "Generating summary for ${RUN_DIR_NAME}" |
| 207 | +
|
| 208 | + docker run --rm --name=benchmarkoor-md \ |
| 209 | + -v "${{ runner.temp }}/results:/app/results" \ |
| 210 | + "${IMAGE}" \ |
| 211 | + generate-markdown-summary \ |
| 212 | + --run-dir="${CONTAINER_RUN_DIR}" \ |
| 213 | + --output="${CONTAINER_RUN_DIR}/summary.md" |
| 214 | +
|
| 215 | + if [ -f "${RUN_DIR_HOST}/summary.md" ]; then |
| 216 | + cat "${RUN_DIR_HOST}/summary.md" >> "$GITHUB_STEP_SUMMARY" |
| 217 | + echo "" >> "$GITHUB_STEP_SUMMARY" |
| 218 | + fi |
| 219 | + done |
| 220 | +
|
| 221 | + - name: Create results archive |
| 222 | + if: always() && inputs.upload-artifacts == 'true' |
| 223 | + shell: bash |
| 224 | + run: | |
| 225 | + if [ -d "${{ runner.temp }}/results" ]; then |
| 226 | + tar -czf "${{ runner.temp }}/benchmarkoor-results.tar.gz" -C "${{ runner.temp }}" results |
| 227 | + fi |
| 228 | +
|
| 229 | + - name: Upload artifacts |
| 230 | + uses: actions/upload-artifact@v4 |
| 231 | + if: always() && inputs.upload-artifacts == 'true' |
| 232 | + with: |
| 233 | + name: benchmarkoor-${{ github.run_id }} |
| 234 | + path: ${{ runner.temp }}/benchmarkoor-results.tar.gz |
| 235 | + |
| 236 | + - name: Cleanup |
| 237 | + shell: bash |
| 238 | + if: always() |
| 239 | + run: | |
| 240 | + echo "Cleaning up" |
| 241 | + rm -rf ${{ runner.temp }}/results |
| 242 | + rm -f ${{ runner.temp }}/benchmarkoor-config-url.yaml |
| 243 | + rm -f ${{ runner.temp }}/benchmarkoor-config-inline.yaml |
| 244 | + rm -f ${{ runner.temp }}/benchmarkoor-results.tar.gz |
| 245 | + docker rm -f benchmarkoor-run 2>/dev/null || true |
| 246 | + docker rm -f benchmarkoor-md 2>/dev/null || true |
0 commit comments