Merge pull request #717 from sjanel/feature/access-log-config-flush-t… #1729
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Benchmarks and GitHub pages Sync | |
| on: | |
| push: | |
| branches: [ main ] | |
| pull_request: | |
| branches: [ main ] | |
| # Weekly scheduled run on main to produce more stable benchmark results | |
| schedule: | |
| - cron: '0 3 * * 0' # every Sunday at 03:00 UTC | |
| # Allow manual runs via the Actions UI with an optional duration override | |
| workflow_dispatch: | |
| inputs: | |
| bench_duration: | |
| description: 'Per-sample benchmark duration (e.g. 90s). Empty = per-job default.' | |
| required: false | |
| default: '' | |
| bench_repeat: | |
| description: 'Samples per case; the median is reported (weekly quality). HTTP/1 + H2 only.' | |
| required: false | |
| default: '3' | |
| h2_protocol: | |
| description: 'H2 protocol filter: h2c, h2-tls, or both' | |
| required: false | |
| default: 'both' | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| jobs: | |
| # ------------------------------------------------------------------ # | |
| # Build: compile the scripted server + client benchmark binaries ONCE.# | |
| # bench / bench-h2 / bench-ws all need the exact same Release build # | |
| # (identical CMake flags) - they only differ in which runtime params # | |
| # they pass to wrk/h2load/k6. Building once and sharing the binaries # | |
| # avoids recompiling aeronet plus every fetched competitor framework # | |
| # (drogon, pistache, crow, beast, uWebSockets, ...) up to 7x per run. # | |
| # ------------------------------------------------------------------ # | |
| build: | |
| name: Build scripted benchmarks | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout current main | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install build dependencies | |
| run: | | |
| sudo apt update | |
| sudo apt install -y build-essential libjsoncpp-dev uuid-dev libssl-dev libcurl4-openssl-dev | |
| - name: Configure benchmark build | |
| run: | | |
| ./scripts/retry.sh cmake -S . -B build-pages -G Ninja \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DAERONET_BUILD_TESTS=OFF \ | |
| -DAERONET_BUILD_EXAMPLES=OFF \ | |
| -DAERONET_BUILD_BENCHMARKS=ON \ | |
| -DAERONET_ENABLE_ASAN=OFF \ | |
| -DAERONET_ENABLE_CLANG_TIDY=OFF \ | |
| -DAERONET_ENABLE_SPDLOG=ON \ | |
| -DAERONET_ENABLE_OPENSSL=ON \ | |
| -DAERONET_ENABLE_HTTP2=ON \ | |
| -DAERONET_ENABLE_BROTLI=ON \ | |
| -DAERONET_ENABLE_ZLIB=ON \ | |
| -DAERONET_ENABLE_ZSTD=ON \ | |
| -DAERONET_ENABLE_OPENTELEMETRY=OFF \ | |
| -DAERONET_ENABLE_WEBSOCKET=ON \ | |
| -DAERONET_ENABLE_ASYNC_HANDLERS=ON | |
| - name: Build | |
| run: | | |
| cmake --build build-pages --parallel | |
| - name: Package build output | |
| run: | | |
| # Some competitor drivers/servers (drogon + its trantor submodule) are built as | |
| # SHARED libraries under build-pages/_deps/ and dynamically linked into the | |
| # drogon-bench-{server,client} binaries. The bench jobs only receive this tarball, | |
| # not the full build tree, so gather every shared object into a dedicated dir that | |
| # travels with the archive. The bench jobs add it to LD_LIBRARY_PATH so the loader | |
| # can resolve libdrogon.so.* / libtrantor.so.* at runtime (otherwise: exit 127, | |
| # "libdrogon.so.1: cannot open shared object file"). | |
| mkdir -p build-pages/benchmarks/shared-libs | |
| find build-pages -path build-pages/benchmarks/shared-libs -prune -o \ | |
| \( -name '*.so' -o -name '*.so.*' \) -print0 \ | |
| | xargs -0 -r cp -a -t build-pages/benchmarks/shared-libs/ | |
| # Preserve symlinks (run_benchmarks.py etc. are symlinked back into the | |
| # checked-out source tree by CMake) and executable bits: a plain tar | |
| # survives actions/upload-artifact intact, unlike zip-based repacking. | |
| tar -czf bench-build-output.tar.gz \ | |
| build-pages/benchmarks/scripted-servers \ | |
| build-pages/benchmarks/scripted-clients \ | |
| build-pages/benchmarks/shared-libs | |
| - name: Upload build artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: bench-build-output | |
| path: bench-build-output.tar.gz | |
| retention-days: 1 | |
| # ------------------------------------------------------------------ # | |
| # Bench: two parallel runs with different wrk connection counts. # | |
| # Both use GCC; low connections measures latency accurately, high # | |
| # connections stresses max throughput. # | |
| # ------------------------------------------------------------------ # | |
| bench: | |
| name: Bench (${{ matrix.conn_label }}) | |
| needs: build | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # Low connections: 10/thread - accurate latency, moderate throughput | |
| - conn_label: low | |
| connections_per_thread: 10 | |
| # High connections: 50/thread - higher throughput, higher latency | |
| - conn_label: high | |
| connections_per_thread: 100 | |
| steps: | |
| - name: Checkout current main | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install runtime dependencies | |
| run: | | |
| sudo apt update | |
| sudo apt install -y wrk libjsoncpp-dev uuid-dev libssl-dev libcurl4-openssl-dev | |
| pip install uvicorn starlette | |
| - name: Download build artifact | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: bench-build-output | |
| path: . | |
| - name: Extract build artifact | |
| run: tar -xzf bench-build-output.tar.gz | |
| - name: Run benchmarks | |
| working-directory: ${{github.workspace}}/build-pages/benchmarks/scripted-servers | |
| env: | |
| # Resolve the shared libs (libdrogon.so.* / libtrantor.so.*) bundled by the build job. | |
| LD_LIBRARY_PATH: ${{github.workspace}}/build-pages/benchmarks/shared-libs | |
| run: | | |
| # Decide duration, threads and sample count based on event type and inputs. | |
| # Defaults: | |
| # - pull_request / non-main push => 5s, 1 thread, 1 sample (fast) | |
| # - push to main => 30s, 2 threads, 1 sample | |
| # - schedule / workflow_dispatch => 45s x 3-sample median, 2 threads (weekly | |
| # quality). Several shorter samples + median beat one long sample on noisy | |
| # shared runners; DUR x REPEAT is kept within the 6h per-job budget across | |
| # all servers x scenarios. Both are overridable via workflow_dispatch inputs. | |
| EVENT_NAME=${GITHUB_EVENT_NAME:-} | |
| REF=${GITHUB_REF:-} | |
| WARMUP=5s | |
| THREADS=1 | |
| REPEAT=1 | |
| CPT=${{ matrix.connections_per_thread }} | |
| CONN=$((THREADS * CPT)) | |
| if [ "$EVENT_NAME" = "push" ] && [ "$REF" = "refs/heads/main" ]; then | |
| DUR=30s | |
| elif [ "$EVENT_NAME" = "workflow_dispatch" ] || [ "$EVENT_NAME" = "schedule" ]; then | |
| REPEAT="${{ github.event.inputs.bench_repeat || '3' }}" | |
| if [ -n "${{ github.event.inputs.bench_duration }}" ]; then | |
| DUR="${{ github.event.inputs.bench_duration }}" | |
| else | |
| DUR=45s | |
| fi | |
| else | |
| # pull_request and non-main pushes | |
| DUR=5s | |
| WARMUP=2s | |
| CONN=$((THREADS * CPT)) | |
| fi | |
| echo "Event: $EVENT_NAME ref: $REF -> ${DUR}x${REPEAT}, $THREADS threads, $CONN connections ($CPT/thread)" | |
| BENCH_WRK_TIMEOUT=${BENCH_WRK_TIMEOUT:-10s} | |
| BODY_CODEC_MAX_PAYLOAD_KB=${BODY_CODEC_MAX_PAYLOAD_KB:-4096} | |
| export BENCH_WRK_TIMEOUT BODY_CODEC_MAX_PAYLOAD_KB | |
| echo "Using BENCH_WRK_TIMEOUT=$BENCH_WRK_TIMEOUT BODY_CODEC_MAX_PAYLOAD_KB=$BODY_CODEC_MAX_PAYLOAD_KB" | |
| ./run_benchmarks.py --duration "$DUR" --threads "$THREADS" --warmup "$WARMUP" --connections "$CONN" --repeat "$REPEAT" | |
| - name: Upload benchmark results | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: bench-results-${{ matrix.conn_label }} | |
| path: build-pages/benchmarks/scripted-servers/results/benchmark_latest.json | |
| retention-days: 3 | |
| - name: Upload badge (high-connections run only) | |
| if: matrix.conn_label == 'high' | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: bench-badge | |
| path: build-pages/benchmarks/scripted-servers/results/benchmark_badge.json | |
| retention-days: 3 | |
| if-no-files-found: ignore | |
| # ------------------------------------------------------------------ # | |
| # HTTP/2 bench: h2c/h2-tls × low/high connections via h2load. # | |
| # ------------------------------------------------------------------ # | |
| bench-h2: | |
| name: H2 Bench (${{ matrix.protocol }}, ${{ matrix.conn_label }}) | |
| needs: build | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - protocol: h2c | |
| conn_label: low | |
| connections_per_thread: 10 | |
| - protocol: h2c | |
| conn_label: high | |
| connections_per_thread: 100 | |
| - protocol: h2-tls | |
| conn_label: low | |
| connections_per_thread: 10 | |
| - protocol: h2-tls | |
| conn_label: high | |
| connections_per_thread: 100 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| - name: Filter protocol (workflow_dispatch) | |
| id: filter | |
| run: | | |
| INPUT_PROTO="${{ github.event.inputs.h2_protocol || 'both' }}" | |
| MATRIX_PROTO="${{ matrix.protocol }}" | |
| if [[ "$INPUT_PROTO" != "both" ]] && [[ "$INPUT_PROTO" != "$MATRIX_PROTO" ]]; then | |
| echo "skip=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "skip=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Install dependencies | |
| if: steps.filter.outputs.skip != 'true' | |
| run: | | |
| sudo apt update | |
| sudo apt install -y nghttp2-client libjsoncpp-dev uuid-dev libssl-dev libcurl4-openssl-dev | |
| pip install uvicorn starlette hypercorn[h2] | |
| h2load --version | |
| - name: Download build artifact | |
| if: steps.filter.outputs.skip != 'true' | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: bench-build-output | |
| path: . | |
| - name: Extract build artifact | |
| if: steps.filter.outputs.skip != 'true' | |
| run: tar -xzf bench-build-output.tar.gz | |
| - name: Run H2 benchmarks | |
| if: steps.filter.outputs.skip != 'true' | |
| working-directory: ${{github.workspace}}/build-pages/benchmarks/scripted-servers | |
| env: | |
| # Resolve the shared libs (libdrogon.so.* / libtrantor.so.*) bundled by the build job. | |
| LD_LIBRARY_PATH: ${{github.workspace}}/build-pages/benchmarks/shared-libs | |
| run: | | |
| EVENT_NAME=${GITHUB_EVENT_NAME:-} | |
| REF=${GITHUB_REF:-} | |
| WARMUP=5s | |
| THREADS=1 | |
| REPEAT=1 | |
| CPT=${{ matrix.connections_per_thread }} | |
| CONN=$((THREADS * CPT)) | |
| H2_STREAMS=10 | |
| # See the HTTP/1 job for the event -> duration/repeat rationale. schedule / | |
| # workflow_dispatch take a 3-sample median at a shorter per-sample duration. | |
| if [ "$EVENT_NAME" = "push" ] && [ "$REF" = "refs/heads/main" ]; then | |
| DUR=30s | |
| elif [ "$EVENT_NAME" = "workflow_dispatch" ] || [ "$EVENT_NAME" = "schedule" ]; then | |
| REPEAT="${{ github.event.inputs.bench_repeat || '3' }}" | |
| if [ -n "${{ github.event.inputs.bench_duration }}" ]; then | |
| DUR="${{ github.event.inputs.bench_duration }}" | |
| else | |
| DUR=45s | |
| fi | |
| else | |
| DUR=5s | |
| WARMUP=2s | |
| CONN=$((THREADS * CPT)) | |
| fi | |
| echo "H2 bench: protocol=${{ matrix.protocol }} dur=${DUR}x${REPEAT} threads=$THREADS conn=$CONN streams=$H2_STREAMS" | |
| ./run_benchmarks.py \ | |
| --protocol "${{ matrix.protocol }}" \ | |
| --duration "$DUR" \ | |
| --threads "$THREADS" \ | |
| --warmup "$WARMUP" \ | |
| --connections "$CONN" \ | |
| --h2-streams "$H2_STREAMS" \ | |
| --repeat "$REPEAT" | |
| - name: Upload H2 results | |
| if: steps.filter.outputs.skip != 'true' | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: h2-results-${{ matrix.protocol }}-${{ matrix.conn_label }} | |
| path: build-pages/benchmarks/scripted-servers/results/benchmark_latest.json | |
| retention-days: 3 | |
| - name: Upload H2 badge (h2-tls high-connections only) | |
| if: steps.filter.outputs.skip != 'true' && matrix.protocol == 'h2-tls' && matrix.conn_label == 'high' | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: h2-bench-badge | |
| path: build-pages/benchmarks/scripted-servers/results/benchmark_badge.json | |
| retention-days: 3 | |
| if-no-files-found: ignore | |
| - name: Upload H2 badge (h2c high-connections only) | |
| if: steps.filter.outputs.skip != 'true' && matrix.protocol == 'h2c' && matrix.conn_label == 'high' | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: h2-bench-badge-h2c | |
| path: build-pages/benchmarks/scripted-servers/results/benchmark_badge.json | |
| retention-days: 3 | |
| if-no-files-found: ignore | |
| # ------------------------------------------------------------------ # | |
| # WebSocket bench: k6-based WebSocket scenarios. # | |
| # ------------------------------------------------------------------ # | |
| bench-ws: | |
| name: WS Bench | |
| needs: build | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install dependencies | |
| run: | | |
| sudo apt update | |
| sudo apt install -y libjsoncpp-dev uuid-dev libssl-dev libcurl4-openssl-dev | |
| - name: Install k6 | |
| run: | | |
| K6_VERSION=v0.55.0 | |
| curl -fsSL "https://github.com/grafana/k6/releases/download/${K6_VERSION}/k6-${K6_VERSION}-linux-amd64.tar.gz" \ | |
| | tar xzf - --strip-components=1 -C /usr/local/bin "k6-${K6_VERSION}-linux-amd64/k6" | |
| k6 version | |
| - name: Download build artifact | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: bench-build-output | |
| path: . | |
| - name: Extract build artifact | |
| run: tar -xzf bench-build-output.tar.gz | |
| - name: Run WebSocket benchmarks | |
| working-directory: ${{github.workspace}}/build-pages/benchmarks/scripted-servers | |
| env: | |
| # Resolve the shared libs (libdrogon.so.* / libtrantor.so.*) bundled by the build job. | |
| LD_LIBRARY_PATH: ${{github.workspace}}/build-pages/benchmarks/shared-libs | |
| run: | | |
| EVENT_NAME=${GITHUB_EVENT_NAME:-} | |
| REF=${GITHUB_REF:-} | |
| VUS=50 | |
| WARMUP=5s | |
| if [ "$EVENT_NAME" = "push" ] && [ "$REF" = "refs/heads/main" ]; then | |
| DUR=30s | |
| elif [ "$EVENT_NAME" = "workflow_dispatch" ] || [ "$EVENT_NAME" = "schedule" ]; then | |
| if [ -n "${{ github.event.inputs.bench_duration }}" ]; then | |
| DUR="${{ github.event.inputs.bench_duration }}" | |
| else | |
| DUR=90s | |
| fi | |
| else | |
| # pull_request and non-main pushes | |
| DUR=5s | |
| WARMUP=2s | |
| VUS=10 | |
| fi | |
| echo "WS bench: dur=$DUR vus=$VUS warmup=$WARMUP" | |
| ./run_ws_benchmarks.py \ | |
| --vus "$VUS" \ | |
| --duration "$DUR" \ | |
| --warmup "$WARMUP" \ | |
| --output ./ws-results | |
| - name: Upload WS results | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: ws-bench-results | |
| path: build-pages/benchmarks/scripted-servers/ws-results/ws_benchmark_latest.json | |
| retention-days: 3 | |
| - name: Upload WS badge | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: ws-bench-badge | |
| path: build-pages/benchmarks/scripted-servers/ws-results/ws_benchmark_badge.json | |
| retention-days: 3 | |
| if-no-files-found: ignore | |
| - name: Upload WS HTML report | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: ws-bench-html | |
| path: build-pages/benchmarks/scripted-servers/ws-results/ws_benchmark_*.html | |
| retention-days: 3 | |
| if-no-files-found: ignore | |
| # ------------------------------------------------------------------ # | |
| # Client bench: aeronet HttpClient vs libcurl / drogon / beast, once # | |
| # per protocol (http1, h2c, h2-tls). Split out into its own job (used # | |
| # to run as a trailing step inside `bench` / `bench-h2`) so it runs # | |
| # in parallel with the server-side matrices instead of stacking # | |
| # after them on the same runner. # | |
| # ------------------------------------------------------------------ # | |
| bench-client: | |
| name: Client Bench (${{ matrix.protocol }}) | |
| needs: build | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - protocol: http1 | |
| artifact_suffix: '' | |
| file_suffix: '' | |
| - protocol: h2c | |
| artifact_suffix: '-h2c' | |
| file_suffix: '_h2c' | |
| - protocol: h2-tls | |
| artifact_suffix: '-h2-tls' | |
| file_suffix: '_h2-tls' | |
| steps: | |
| - name: Checkout current main | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| - name: Filter protocol (workflow_dispatch) | |
| id: filter | |
| run: | | |
| INPUT_PROTO="${{ github.event.inputs.h2_protocol || 'both' }}" | |
| MATRIX_PROTO="${{ matrix.protocol }}" | |
| if [[ "$MATRIX_PROTO" != "http1" ]] && [[ "$INPUT_PROTO" != "both" ]] && [[ "$INPUT_PROTO" != "$MATRIX_PROTO" ]]; then | |
| echo "skip=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "skip=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Install runtime dependencies | |
| if: steps.filter.outputs.skip != 'true' | |
| run: | | |
| sudo apt update | |
| sudo apt install -y libjsoncpp-dev uuid-dev libssl-dev libcurl4-openssl-dev | |
| - name: Download build artifact | |
| if: steps.filter.outputs.skip != 'true' | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: bench-build-output | |
| path: . | |
| - name: Extract build artifact | |
| if: steps.filter.outputs.skip != 'true' | |
| run: tar -xzf bench-build-output.tar.gz | |
| - name: Run client benchmarks | |
| if: steps.filter.outputs.skip != 'true' | |
| working-directory: ${{github.workspace}}/build-pages/benchmarks/scripted-clients | |
| env: | |
| # Resolve the shared libs (libdrogon.so.* / libtrantor.so.*) bundled by the build job. | |
| LD_LIBRARY_PATH: ${{github.workspace}}/build-pages/benchmarks/shared-libs | |
| run: | | |
| EVENT_NAME=${GITHUB_EVENT_NAME:-} | |
| REF=${GITHUB_REF:-} | |
| WARMUP=5s | |
| THREADS=1 | |
| if [ "$EVENT_NAME" = "push" ] && [ "$REF" = "refs/heads/main" ]; then | |
| DUR=30s | |
| elif [ "$EVENT_NAME" = "workflow_dispatch" ] || [ "$EVENT_NAME" = "schedule" ]; then | |
| if [ -n "${{ github.event.inputs.bench_duration }}" ]; then | |
| DUR="${{ github.event.inputs.bench_duration }}" | |
| else | |
| DUR=90s | |
| fi | |
| else | |
| # pull_request and non-main pushes | |
| DUR=5s | |
| WARMUP=2s | |
| fi | |
| echo "Client bench: protocol=${{ matrix.protocol }} dur=$DUR threads=$THREADS warmup=$WARMUP" | |
| ./run_client_benchmarks.py \ | |
| --protocol "${{ matrix.protocol }}" \ | |
| --duration "$DUR" \ | |
| --threads "$THREADS" \ | |
| --warmup "$WARMUP" \ | |
| --output "$PWD/results" | |
| - name: Upload client results | |
| if: steps.filter.outputs.skip != 'true' | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: client-bench-results${{ matrix.artifact_suffix }} | |
| path: build-pages/benchmarks/scripted-clients/results/client_benchmark_latest${{ matrix.file_suffix }}.json | |
| retention-days: 3 | |
| - name: Upload client badge | |
| if: steps.filter.outputs.skip != 'true' | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: client-bench-badge${{ matrix.artifact_suffix }} | |
| path: build-pages/benchmarks/scripted-clients/results/client_benchmark_badge${{ matrix.file_suffix }}.json | |
| retention-days: 3 | |
| if-no-files-found: ignore | |
| # ------------------------------------------------------------------ # | |
| # Publish: aggregate all benchmark results and upload the assembled # | |
| # site as a GitHub Pages artifact (deployed by the `deploy` job). # | |
| # ------------------------------------------------------------------ # | |
| publish: | |
| name: Publish Pages | |
| runs-on: ubuntu-latest | |
| needs: [bench, bench-h2, bench-ws, bench-client] | |
| if: always() && !cancelled() | |
| steps: | |
| - name: Checkout current main | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| - name: Assemble site content from main | |
| run: | | |
| rm -rf /tmp/site | |
| python3 -m pip install --disable-pip-version-check --quiet --requirement requirements-docs.txt | |
| python3 -m mkdocs build --strict --site-dir /tmp/site | |
| # Retain the source Markdown at its historical URLs. The generated site | |
| # is served at the Pages root; benchmark dashboards are added below. | |
| rsync -a docs/ /tmp/site/docs/ | |
| rsync -a resources/ /tmp/site/resources/ | |
| - name: Download all benchmark results | |
| uses: actions/download-artifact@v8 | |
| with: | |
| path: /tmp/bench-artifacts | |
| - name: Render HTML for Pages | |
| run: | | |
| rm -fr /tmp/site/benchmarks | |
| mkdir -p /tmp/site/benchmarks /tmp/site/benchmarks/h2 | |
| # --- HTTP/1.1 results --- | |
| INPUTS=() | |
| for label in low high; do | |
| json="/tmp/bench-artifacts/bench-results-${label}/benchmark_latest.json" | |
| if [[ -f "$json" ]]; then | |
| INPUTS+=("--input" "$json") | |
| cp "$json" "/tmp/site/benchmarks/benchmark_${label}.json" | |
| fi | |
| done | |
| if [[ ${#INPUTS[@]} -gt 0 ]]; then | |
| benchmarks/scripted-servers/render_benchmarks_html.py \ | |
| "${INPUTS[@]}" \ | |
| --output /tmp/site/benchmarks/index.html | |
| else | |
| echo "WARNING: No HTTP/1.1 benchmark results found; skipping render" | |
| fi | |
| # Copy HTTP/1.1 badge if available | |
| if [[ -f /tmp/bench-artifacts/bench-badge/benchmark_badge.json ]]; then | |
| cp /tmp/bench-artifacts/bench-badge/benchmark_badge.json /tmp/site/benchmarks/benchmark_badge.json | |
| fi | |
| # --- HTTP/2 results --- | |
| for proto in h2c h2-tls; do | |
| H2_INPUTS=() | |
| for label in low high; do | |
| json="/tmp/bench-artifacts/h2-results-${proto}-${label}/benchmark_latest.json" | |
| if [[ -f "$json" ]]; then | |
| H2_INPUTS+=("--input" "$json") | |
| cp "$json" "/tmp/site/benchmarks/h2/benchmark_${proto}_${label}.json" | |
| fi | |
| done | |
| if [[ ${#H2_INPUTS[@]} -gt 0 ]]; then | |
| benchmarks/scripted-servers/render_benchmarks_html.py \ | |
| "${H2_INPUTS[@]}" \ | |
| --output "/tmp/site/benchmarks/h2/benchmarks_${proto}.html" | |
| fi | |
| done | |
| # Copy H2 badges if available | |
| if [[ -f /tmp/bench-artifacts/h2-bench-badge/benchmark_badge.json ]]; then | |
| cp /tmp/bench-artifacts/h2-bench-badge/benchmark_badge.json /tmp/site/benchmarks/h2/benchmark_badge.json | |
| fi | |
| if [[ -f /tmp/bench-artifacts/h2-bench-badge-h2c/benchmark_badge.json ]]; then | |
| cp /tmp/bench-artifacts/h2-bench-badge-h2c/benchmark_badge.json /tmp/site/benchmarks/h2/benchmark_badge_h2c.json | |
| fi | |
| # --- WebSocket results --- | |
| mkdir -p /tmp/site/benchmarks/ws | |
| WS_JSON="/tmp/bench-artifacts/ws-bench-results/ws_benchmark_latest.json" | |
| if [[ -f "$WS_JSON" ]]; then | |
| cp "$WS_JSON" /tmp/site/benchmarks/ws/ws_benchmark_latest.json | |
| python3 benchmarks/scripted-servers/render_benchmarks_html.py \ | |
| --input "$WS_JSON" \ | |
| --output /tmp/site/benchmarks/ws/index.html | |
| else | |
| echo "WARNING: No WebSocket benchmark results found; skipping render" | |
| fi | |
| # Copy WS badge if available | |
| if [[ -f /tmp/bench-artifacts/ws-bench-badge/ws_benchmark_badge.json ]]; then | |
| cp /tmp/bench-artifacts/ws-bench-badge/ws_benchmark_badge.json /tmp/site/benchmarks/ws/ws_benchmark_badge.json | |
| fi | |
| # Copy WS HTML report if available | |
| for f in /tmp/bench-artifacts/ws-bench-html/ws_benchmark_*.html; do | |
| [[ -f "$f" ]] && cp "$f" /tmp/site/benchmarks/ws/ || true | |
| done | |
| # --- HTTP client results (aeronet HttpClient vs libcurl/drogon/beast) --- | |
| # Rendered by the very same render_benchmarks_html.py: the client orchestrator emits the | |
| # identical summary schema (clients on the 'servers' axis). | |
| mkdir -p /tmp/site/benchmarks/clients | |
| CLIENT_JSON="/tmp/bench-artifacts/client-bench-results/client_benchmark_latest.json" | |
| if [[ -f "$CLIENT_JSON" ]]; then | |
| cp "$CLIENT_JSON" /tmp/site/benchmarks/clients/client_benchmark_latest.json | |
| benchmarks/scripted-servers/render_benchmarks_html.py \ | |
| --input "$CLIENT_JSON" \ | |
| --output /tmp/site/benchmarks/clients/index.html | |
| else | |
| echo "WARNING: No client benchmark results found; skipping render" | |
| fi | |
| # Copy client badge if available | |
| if [[ -f /tmp/bench-artifacts/client-bench-badge/client_benchmark_badge.json ]]; then | |
| cp /tmp/bench-artifacts/client-bench-badge/client_benchmark_badge.json /tmp/site/benchmarks/clients/client_benchmark_badge.json | |
| fi | |
| # --- HTTP/2 client results (h2c / h2-tls) --- | |
| # Same renderer as the HTTP/1.1 client dashboard; one HTML page + badge per protocol. | |
| for proto in h2c h2-tls; do | |
| CJSON="/tmp/bench-artifacts/client-bench-results-${proto}/client_benchmark_latest_${proto}.json" | |
| if [[ -f "$CJSON" ]]; then | |
| cp "$CJSON" "/tmp/site/benchmarks/clients/client_benchmark_latest_${proto}.json" | |
| benchmarks/scripted-servers/render_benchmarks_html.py \ | |
| --input "$CJSON" \ | |
| --output "/tmp/site/benchmarks/clients/client_benchmark_${proto}.html" | |
| else | |
| echo "WARNING: No ${proto} client benchmark results found; skipping render" | |
| fi | |
| CBADGE="/tmp/bench-artifacts/client-bench-badge-${proto}/client_benchmark_badge_${proto}.json" | |
| if [[ -f "$CBADGE" ]]; then | |
| cp "$CBADGE" "/tmp/site/benchmarks/clients/client_benchmark_badge_${proto}.json" | |
| fi | |
| done | |
| - name: Upload Pages artifact | |
| if: ${{ github.event_name != 'pull_request' }} | |
| uses: actions/upload-pages-artifact@v5 | |
| with: | |
| path: /tmp/site | |
| # ------------------------------------------------------------------ # | |
| # Deploy: publish the uploaded artifact to GitHub Pages natively via # | |
| # actions/deploy-pages (no gh-pages branch). Skipped for PRs. # | |
| # ------------------------------------------------------------------ # | |
| deploy: | |
| name: Deploy Pages | |
| runs-on: ubuntu-latest | |
| needs: publish | |
| if: ${{ github.event_name != 'pull_request' }} | |
| permissions: | |
| pages: write | |
| id-token: write | |
| environment: | |
| name: github-pages | |
| url: ${{ steps.deployment.outputs.page_url }} | |
| steps: | |
| - name: Deploy to GitHub Pages | |
| id: deployment | |
| uses: actions/deploy-pages@v5 | |
| env: | |
| # Silence the Node DEP0040 punycode deprecation warning emitted from within the action. | |
| NODE_OPTIONS: --no-deprecation |