Skip to content

Commit 900bd4e

Browse files
authored
Merge pull request #255 from MDA2AV/multi/site-command
add --save to pr command and update site docs
2 parents 488e5f1 + d36b420 commit 900bd4e

6 files changed

Lines changed: 107 additions & 30 deletions

File tree

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,6 @@
1313
| `/benchmark` | Run all benchmark tests |
1414
| `/benchmark -t baseline` | Run a specific test |
1515
| `/benchmark -f <framework> -t <test>` | Run a specific framework and test |
16+
| `/benchmark --save` | Run and save results (updates leaderboard on merge) |
17+
18+
Results are automatically compared against the current leaderboard.

.github/workflows/benchmark-pr.yml

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,13 @@ on:
1313
description: 'Profile (e.g. baseline, baseline-h2, leave empty for all)'
1414
required: false
1515
default: ''
16+
save:
17+
description: 'Save results (true/false)'
18+
required: false
19+
default: ''
1620

1721
permissions:
18-
contents: read
22+
contents: write
1923
pull-requests: write
2024

2125
concurrency:
@@ -35,9 +39,28 @@ jobs:
3539
id: bench
3640
run: |
3741
log=$(mktemp)
38-
./scripts/benchmark.sh "${{ inputs.framework }}" ${{ inputs.profile }} 2>&1 | tee "$log"
42+
SAVE_FLAG=""
43+
if [ "${{ inputs.save }}" = "true" ]; then
44+
SAVE_FLAG="--save"
45+
fi
46+
./scripts/benchmark.sh "${{ inputs.framework }}" ${{ inputs.profile }} $SAVE_FLAG 2>&1 | tee "$log"
3947
echo "log_file=$log" >> "$GITHUB_OUTPUT"
4048
49+
- name: Commit saved results
50+
if: inputs.save == 'true'
51+
run: |
52+
git config user.name "github-actions[bot]"
53+
git config user.email "github-actions[bot]@users.noreply.github.com"
54+
git add results/ site/data/ site/static/logs/ 2>/dev/null || true
55+
if git diff --cached --quiet; then
56+
echo "No results to commit"
57+
else
58+
git commit -m "Benchmark results: ${{ inputs.framework }} ${{ inputs.profile }}"
59+
git push origin HEAD:refs/pull/${{ inputs.pr }}/head
60+
fi
61+
env:
62+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
63+
4164
- name: Compare with main
4265
id: compare
4366
run: |

.github/workflows/pr-commands.yml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,18 @@ jobs:
4040
EXPLICIT_TEST=$(echo "$COMMENT_BODY" | grep -oP '/benchmark\s+\K[^-]\S*' || echo "")
4141
fi
4242
43+
# Parse --save flag
44+
SAVE_FLAG=""
45+
if echo "$COMMENT_BODY" | grep -q '\-\-save'; then
46+
SAVE_FLAG="true"
47+
fi
48+
4349
FRAMEWORK="${EXPLICIT_FW:-$AUTO_FRAMEWORK}"
4450
echo "framework=$FRAMEWORK" >> "$GITHUB_OUTPUT"
4551
echo "profile=$EXPLICIT_TEST" >> "$GITHUB_OUTPUT"
52+
echo "save=$SAVE_FLAG" >> "$GITHUB_OUTPUT"
4653
echo "Detected framework: $FRAMEWORK (auto: $AUTO_FRAMEWORK, explicit: $EXPLICIT_FW)"
47-
echo "Profile: $EXPLICIT_TEST"
54+
echo "Profile: $EXPLICIT_TEST, Save: $SAVE_FLAG"
4855
4956
elif echo "$COMMENT_BODY" | grep -q '/validate'; then
5057
echo "command=validate" >> "$GITHUB_OUTPUT"
@@ -89,9 +96,10 @@ jobs:
8996
gh workflow run benchmark-pr.yml \
9097
-f pr=${{ steps.parse.outputs.pr }} \
9198
-f framework=${{ steps.parse.outputs.framework }} \
92-
-f profile="${{ steps.parse.outputs.profile }}"
99+
-f profile="${{ steps.parse.outputs.profile }}" \
100+
-f save="${{ steps.parse.outputs.save }}"
93101
94-
gh pr comment "${{ steps.parse.outputs.pr }}" --body "🚀 Benchmark run triggered for \`${{ steps.parse.outputs.framework }}\`${{ steps.parse.outputs.profile && format(' (test: {0})', steps.parse.outputs.profile) || ' (all tests)' }}. Results will be posted here when done."
102+
gh pr comment "${{ steps.parse.outputs.pr }}" --body "🚀 Benchmark run triggered for \`${{ steps.parse.outputs.framework }}\`${{ steps.parse.outputs.profile && format(' (test: {0})', steps.parse.outputs.profile) || ' (all tests)' }}${{ steps.parse.outputs.save == 'true' && ' with --save' || '' }}. Results will be posted here when done."
95103
env:
96104
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
97105

README.md

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,17 @@ HTTP framework benchmark platform.
1212

1313
Tag **@BennyFranciscus** on your PR for help with implementation or benchmark questions.
1414

15-
| Command | Action |
16-
|---------|--------|
17-
| `/validate` | Run the 18-point validation suite |
18-
| `/benchmark` | Run all benchmark profiles |
19-
| `/benchmark baseline` | Run a specific profile |
15+
| Command | Description |
16+
|---------|-------------|
17+
| `/validate` | Run the 18-point validation suite (auto-detects framework from PR) |
18+
| `/validate -f <framework>` | Validate a specific framework |
19+
| `/benchmark` | Run all benchmark tests (auto-detects framework) |
20+
| `/benchmark -t <test>` | Run a specific test profile |
21+
| `/benchmark -f <framework> -t <test>` | Run a specific framework and test |
22+
| `/benchmark --save` | Run and save results (updates leaderboard on merge) |
23+
| `/benchmark -f <framework> -t <test> --save` | Run, compare with main, and save results |
24+
25+
Results are automatically compared against the current leaderboard and deltas are posted in the PR comment.
2026

2127
---
2228

site/content/docs/add-framework/ci.md

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,40 +2,66 @@
22
title: CI & Runner
33
---
44

5-
## GitHub Actions
5+
## PR Commands
66

7-
HttpArena uses four GitHub Actions workflows to automate validation, benchmarking, and deployment.
7+
Comment on any PR to trigger validation or benchmarks. The framework is auto-detected from changed files, or you can specify it explicitly.
88

9-
### Validate Framework
9+
| Command | Description |
10+
|---------|-------------|
11+
| `/validate` | Run the 18-point validation suite |
12+
| `/validate -f <framework>` | Validate a specific framework |
13+
| `/benchmark` | Run all benchmark tests |
14+
| `/benchmark -t <test>` | Run a specific test profile |
15+
| `/benchmark -f <framework> -t <test>` | Run a specific framework and test |
16+
| `/benchmark --save` | Run and save results (updates leaderboard on merge) |
1017

11-
**Trigger:** Automatically on every PR that modifies files under `frameworks/` or `scripts/validate.sh`.
18+
### Flags
1219

13-
Detects which frameworks were changed in the PR and runs `./scripts/validate.sh` against each one. If validation fails, the PR check fails — you must fix the issues before merging.
20+
- **`-f <framework>`** — Override auto-detection. Use the directory name under `frameworks/` (e.g. `-f actix`, `-f go-fasthttp`).
21+
- **`-t <test>`** — Run a specific test profile (e.g. `-t baseline`, `-t mixed`, `-t async-db`).
22+
- **`--save`** — Save benchmark results to the PR branch. When the PR is merged, results are included in the next site deployment and appear on the leaderboard.
1423

15-
### Benchmark
24+
### Comparison with main
1625

17-
**Trigger:** Automatically when a push to `main` modifies files under `frameworks/`, or manually via workflow dispatch.
26+
After every benchmark run, results are automatically compared against the current published data on main. A delta table is posted in the PR comment showing changes in RPS, latency, CPU, and memory for each connection count. New frameworks with no prior results show "NEW" instead of deltas.
27+
28+
## GitHub Actions
29+
30+
HttpArena uses four GitHub Actions workflows.
31+
32+
### PR Commands (`pr-commands.yml`)
1833

19-
When triggered automatically, it detects which frameworks changed in the latest commit and benchmarks only those. When triggered manually, you can specify:
20-
- **Framework** — a specific framework name, or leave empty to benchmark all changed frameworks
21-
- **Profile** — a specific test profile (e.g. `baseline`, `baseline-h2`), or leave empty to run all profiles
34+
**Trigger:** Comment on a PR containing `/validate` or `/benchmark`.
2235

23-
Results are committed and pushed to `main` automatically by the HttpArena Bot.
36+
Parses the command and flags from the comment, detects the framework from changed PR files (or uses the `-f` flag), and either runs validation directly or dispatches the benchmark workflow. Adds a rocket reaction to the comment and posts results when done.
2437

25-
### Benchmark PR
38+
### Benchmark PR (`benchmark-pr.yml`)
2639

27-
**Trigger:** Manual only (workflow dispatch). Requires a PR number and framework name.
40+
**Trigger:** Dispatched by the PR Commands workflow, or manually via workflow dispatch.
2841

29-
Checks out the PR branch, runs the benchmark, and posts the results as a comment on the PR. This lets maintainers benchmark a new framework submission before merging, so contributors can see how their implementation performs on the hosted runner. An optional profile parameter lets you run a specific test instead of the full suite.
42+
Checks out the PR branch, runs the benchmark with optional `--save`, compares results against main using `scripts/compare.sh`, and posts a comment with raw results and a comparison table. If `--save` is used, results are committed and pushed to the PR branch.
3043

31-
### Deploy Site
44+
### Benchmark (`benchmark.yml`)
45+
46+
**Trigger:** Automatically when a push to `main` modifies files under `frameworks/`, or manually via workflow dispatch.
47+
48+
Detects which frameworks changed and benchmarks them with `--save`. Results are committed to `main` and the site data is rebuilt.
49+
50+
### Deploy Site (`deploy.yml`)
3251

3352
**Trigger:** Automatically when a push to `main` modifies files under `site/`, or manually via workflow dispatch.
3453

35-
Builds the Hugo site and deploys it to GitHub Pages. This runs on GitHub-hosted Ubuntu runners (not the self-hosted runner).
54+
Builds the Hugo site and deploys it to GitHub Pages. Runs on GitHub-hosted runners (not the self-hosted benchmark machine).
55+
56+
## Hosted Runner
3657

37-
## Hosted runner
58+
The Validate, Benchmark, and Benchmark PR workflows run on a **self-hosted runner** — a dedicated 64-core bare-metal machine configured for reproducible benchmarking:
3859

39-
The Validate, Benchmark, and Benchmark PR workflows run on a **self-hosted runner** — a dedicated bare-metal machine configured for reproducible, low-noise benchmarking. This ensures all frameworks are tested on identical hardware under controlled conditions, with CPU governors locked, background services minimized, and no resource contention from other CI jobs.
60+
- CPU governor locked to `performance` mode during benchmarks
61+
- Kernel caches dropped between runs
62+
- Docker daemon restarted for clean state
63+
- `somaxconn` and TCP backlog tuned for high connection counts
64+
- `ulimit` set to maximum file descriptors
65+
- Host networking for minimal overhead
4066

41-
Only the Deploy Site workflow uses GitHub-hosted runners, since it only builds static HTML and doesn't need controlled hardware.
67+
Only the Deploy Site workflow uses GitHub-hosted runners.

site/content/docs/add-framework/meta-json.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ Create a `meta.json` file in your framework directory:
4141
| `upload` | HTTP/1.1 | `/upload` |
4242
| `compression` | HTTP/1.1 | `/compression` |
4343
| `noisy` | HTTP/1.1 | `/baseline11` |
44-
| `mixed` | HTTP/1.1 | `/baseline11`, `/json`, `/db`, `/upload`, `/compression` |
44+
| `mixed` | HTTP/1.1 | `/baseline11`, `/json`, `/db`, `/upload`, `/compression`, `/static/*`, `/async-db` |
4545
| `static` | HTTP/1.1 | `/static/*` (port 8080) |
46+
| `async-db` | HTTP/1.1 | `/async-db` (requires `DATABASE_URL` env var) |
4647
| `baseline-h2` | HTTP/2 | `/baseline2` (TLS, port 8443) |
4748
| `static-h2` | HTTP/2 | `/static/*` (TLS, port 8443) |
4849
| `baseline-h3` | HTTP/3 | `/baseline2` (QUIC, port 8443) |
@@ -52,3 +53,13 @@ Create a `meta.json` file in your framework directory:
5253
| `echo-ws` | WebSocket | `/ws` echo (port 8080) |
5354

5455
Only include profiles your framework supports. Frameworks missing a profile simply don't appear in that profile's leaderboard.
56+
57+
### async-db
58+
59+
The `async-db` profile requires an async PostgreSQL driver. The benchmark script starts a Postgres sidecar with 100K rows and passes `DATABASE_URL=postgres://bench:bench@localhost:5432/benchmark` to your container. Your framework must:
60+
61+
1. Connect to Postgres using the `DATABASE_URL` environment variable
62+
2. Implement `GET /async-db?min=X&max=Y` that queries: `SELECT id, name, category, price, quantity, active, tags, rating_score, rating_count FROM items WHERE price BETWEEN $1 AND $2 LIMIT 50`
63+
3. Return JSON: `{"items": [...], "count": N}` with nested `rating: {score, count}` and `tags` as a JSON array
64+
4. Return `{"items":[],"count":0}` if the database is unavailable
65+
5. Use lazy connection initialization — retry connecting if Postgres isn't ready at startup

0 commit comments

Comments
 (0)