diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index 2ca54c5..a074cf9 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -125,6 +125,8 @@ jobs: runs-on: ubuntu-latest needs: [linux, windows] steps: + - uses: actions/checkout@v4 + - name: Download benchmark artifacts uses: actions/download-artifact@v4 with: @@ -132,48 +134,12 @@ jobs: pattern: benchmark-* - name: Prepare Pages content - shell: bash - run: | - set -euo pipefail - RUN_ID="${GITHUB_RUN_ID}" - OUT_DIR="site/benchmarks/runs/${RUN_ID}" - - mkdir -p "${OUT_DIR}" - - # Keep artifact directories separated to avoid collisions. - for d in artifacts/*; do - if [ -d "$d" ]; then - name="$(basename "$d")" - mkdir -p "${OUT_DIR}/${name}" - cp -R "$d"/* "${OUT_DIR}/${name}"/ || true - fi - done - - # No Jekyll processing (serve files as-is) - touch site/.nojekyll - - # Write pointer to the latest run. - python3 - <<'PY' - import json, os - repo = os.environ.get('GITHUB_REPOSITORY', '') - run_id = int(os.environ.get('GITHUB_RUN_ID', '0')) - run_url = f"https://github.com/{repo}/actions/runs/{run_id}" if repo and run_id else None - artifacts_dir = 'artifacts' - artifacts = [] - if os.path.isdir(artifacts_dir): - for name in sorted(os.listdir(artifacts_dir)): - full = os.path.join(artifacts_dir, name) - if os.path.isdir(full) and name.startswith('benchmark-'): - artifacts.append(name) - data = { - 'runId': run_id, - 'runUrl': run_url, - 'artifacts': artifacts, - } - os.makedirs('site/benchmarks', exist_ok=True) - with open('site/benchmarks/latest.json', 'w', encoding='utf-8') as f: - json.dump(data, f, ensure_ascii=False, indent=2) - PY + run: >- + python3 scripts/publish_benchmarks_to_pages.py + --artifacts-dir artifacts + --site-dir site + --repo "${{ github.repository }}" + --run-id "${{ github.run_id }}" - name: Deploy to gh-pages uses: peaceiris/actions-gh-pages@v4 diff --git a/README.md b/README.md index 9dc6948..082bd2e 100644 --- a/README.md +++ b/README.md @@ -94,12 +94,6 @@ This library is header-only, so you only need to specify the include path. g++ -I ./libcpprime -O3 Main.cpp ``` -# Benchmarks - -The benchmark is run on GitHub Actions' Linux with gcc with -O3 optimization enabled. - -You can find more detailed benchmark results by clicking [here](https://github.com/Rac75116/libcpprime/actions/workflows/bench.yml?query=branch%3Amain+is%3Acompleted). - # Releases - 2025/12/21 ver 1.3.0 diff --git a/scripts/publish_benchmarks_to_pages.py b/scripts/publish_benchmarks_to_pages.py new file mode 100644 index 0000000..c784037 --- /dev/null +++ b/scripts/publish_benchmarks_to_pages.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import argparse +import json +import shutil +import zipfile +from pathlib import Path + + +def _safe_rmtree(path: Path) -> None: + if path.exists(): + shutil.rmtree(path) + + +def _copy_tree(src: Path, dst: Path) -> None: + dst.mkdir(parents=True, exist_ok=True) + for item in src.iterdir(): + target = dst / item.name + if item.is_dir(): + shutil.copytree(item, target, dirs_exist_ok=True) + else: + shutil.copy2(item, target) + + +def _extract_zip(zip_path: Path, dst: Path) -> None: + dst.mkdir(parents=True, exist_ok=True) + with zipfile.ZipFile(zip_path) as z: + z.extractall(dst) + + +def main() -> int: + parser = argparse.ArgumentParser( + description="Publish benchmark artifacts to GitHub Pages (fixed latest path)." + ) + parser.add_argument("--artifacts-dir", required=True) + parser.add_argument("--site-dir", required=True) + parser.add_argument("--repo", required=True, help="owner/repo") + parser.add_argument("--run-id", required=True) + args = parser.parse_args() + + artifacts_dir = Path(args.artifacts_dir) + site_dir = Path(args.site_dir) + + repo = args.repo + run_id = int(args.run_id) + run_url = ( + f"https://github.com/{repo}/actions/runs/{run_id}" if repo and run_id else None + ) + + # Fixed, always-latest path. + benchmarks_dir = site_dir / "benchmarks" + latest_dir = benchmarks_dir / "latest" + + # Start fresh to avoid stale files from older runs. + latest_dir.mkdir(parents=True, exist_ok=True) + _safe_rmtree(latest_dir) + latest_dir.mkdir(parents=True, exist_ok=True) + + published_artifacts: list[str] = [] + + if artifacts_dir.exists(): + for entry in sorted(artifacts_dir.iterdir(), key=lambda p: p.name): + name = entry.name + + if entry.is_dir(): + # actions/download-artifact typically extracts into a directory per artifact. + if not name.startswith("benchmark-"): + continue + _copy_tree(entry, latest_dir / name) + published_artifacts.append(name) + continue + + if entry.is_file() and entry.suffix.lower() == ".zip": + base = entry.stem + if not base.startswith("benchmark-"): + continue + _extract_zip(entry, latest_dir / base) + published_artifacts.append(base) + continue + + # No Jekyll processing (serve files as-is) + site_dir.mkdir(parents=True, exist_ok=True) + (site_dir / ".nojekyll").write_text("", encoding="utf-8") + + benchmarks_dir.mkdir(parents=True, exist_ok=True) + + latest_json = { + "runId": run_id, + "runUrl": run_url, + "artifacts": published_artifacts, + "baseUrl": "/benchmarks/latest", + } + + (benchmarks_dir / "latest.json").write_text( + json.dumps(latest_json, ensure_ascii=False, indent=2) + "\n", encoding="utf-8" + ) + + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())