Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,4 @@ jobs:
$drive = $env:GITHUB_WORKSPACE.Substring(0, 1).ToLowerInvariant()
$path = $env:GITHUB_WORKSPACE.Substring(2).Replace('\', '/')
$linuxWorkspace = "/mnt/$drive$path"
wsl --distribution Ubuntu --user root -- bash -lc "set -eu; cd '$linuxWorkspace'; sed -i 's/\r$//' tests/full_validate.sh tests/validate.sh; apt-get update -qq; apt-get install -y -qq python3-venv python3.14-venv; python3 -m venv /tmp/base-cli-venv; . /tmp/base-cli-venv/bin/activate; python -m pip install '.[dev,typer,quality]'; bash tests/full_validate.sh"
wsl --distribution Ubuntu --user root -- bash -lc "set -eu; cd '$linuxWorkspace'; sed -i 's/\r$//' tests/full_validate.sh tests/validate.sh; apt-get update -qq; apt-get install -y -qq python3-venv python3.14-venv; python3 -m venv /tmp/base-cli-venv; . /tmp/base-cli-venv/bin/activate; python -m pip install '.[dev,typer,quality]'; export BASE_CLI_BENCHMARK_PLATFORM=wsl; bash tests/full_validate.sh"
11 changes: 8 additions & 3 deletions docs/performance.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,17 @@ Cyclopts. Install the optional benchmark extra to include Cyclopts:
python -m pip install 'base-cli[benchmark]'
```

The CI quality job checks the base-cli sample p95 against these budgets:
The CI quality job checks the base-cli sample p95 against these budgets. The
benchmark records the selected platform profile in both text and JSON output;
set `BASE_CLI_BENCHMARK_PLATFORM` when a runner's filesystem or virtualization
boundary is not represented by the host operating system. Supported profiles
are `unix`, `macos`, `windows`, and `wsl`.

| Measurement | Budget |
| --- | ---: |
| Fresh `import base_cli` (Unix) | 750 ms |
| Fresh `import base_cli` (Windows) | 1,000 ms |
| Fresh `import base_cli` (native Unix/macOS) | 750 ms |
| Fresh `import base_cli` (native Windows) | 1,000 ms |
| Fresh `import base_cli` (WSL2 on a Windows-mounted checkout) | 1,000 ms |
| Isolated invocation and runtime filesystem setup | 1,500 ms |

The benchmark reports the median, p95, and maximum for seven samples. Pass
Expand Down
55 changes: 50 additions & 5 deletions scripts/benchmark_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,44 @@
from pathlib import Path
from typing import Any, TypedDict, cast

# Windows hosted runners have a materially slower fresh Python process start
# (the import probe includes that process startup by design). Keep the tighter
# budget on Unix while allowing the documented Windows baseline headroom.
IMPORT_P95_BUDGET_MS = 1_000.0 if os.name == "nt" else 750.0
# Fresh-process startup is materially slower on native Windows and on WSL
# when the checkout is on the Windows-mounted filesystem. CI can select the
# platform explicitly with BASE_CLI_BENCHMARK_PLATFORM; the fallback keeps
# local runs useful without requiring a setting.
IMPORT_P95_BUDGETS_MS = {
"unix": 750.0,
"macos": 750.0,
"windows": 1_000.0,
"wsl": 1_000.0,
}


def _is_wsl() -> bool:
try:
proc_version = Path("/proc/version").read_text(encoding="utf-8").lower()
except OSError:
return False
return "microsoft" in proc_version or "wsl" in proc_version


def _benchmark_platform() -> str:
configured = os.environ.get("BASE_CLI_BENCHMARK_PLATFORM", "").strip().lower()
if configured:
if configured not in IMPORT_P95_BUDGETS_MS:
supported = ", ".join(sorted(IMPORT_P95_BUDGETS_MS))
raise ValueError(f"BASE_CLI_BENCHMARK_PLATFORM must be one of {supported}; got {configured!r}")
return configured
if os.name == "nt":
return "windows"
if sys.platform == "darwin":
return "macos"
if _is_wsl():
return "wsl"
return "unix"


BENCHMARK_PLATFORM = _benchmark_platform()
IMPORT_P95_BUDGET_MS = IMPORT_P95_BUDGETS_MS[BENCHMARK_PLATFORM]
INVOCATION_P95_BUDGET_MS = 1_500.0
DEFAULT_ITERATIONS = 7
FRAMEWORKS = ("base-cli", "click", "typer", "cyclopts")
Expand Down Expand Up @@ -69,8 +103,19 @@ def main() -> int:
"invocation_ms": _summary(_measure_invocations(args.iterations, framework)),
}
if args.json:
print(json.dumps({"iterations": args.iterations, "frameworks": metrics}, sort_keys=True))
print(
json.dumps(
{
"iterations": args.iterations,
"platform": BENCHMARK_PLATFORM,
"import_p95_budget_ms": IMPORT_P95_BUDGET_MS,
"frameworks": metrics,
},
sort_keys=True,
)
)
else:
print(f"benchmark platform: {BENCHMARK_PLATFORM} (import p95 budget {IMPORT_P95_BUDGET_MS:.0f} ms)")
for framework, result in metrics.items():
if result.get("status") == "unavailable":
print(f"{framework}: unavailable (install it to include this comparison)")
Expand Down
6 changes: 6 additions & 0 deletions tests/test_benchmark_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,9 @@ def test_framework_comparison_has_stable_public_set(self) -> None:
benchmark_runtime.FRAMEWORKS,
("base-cli", "click", "typer", "cyclopts"),
)

def test_platform_profiles_have_explicit_import_budgets(self) -> None:
self.assertEqual(benchmark_runtime.IMPORT_P95_BUDGETS_MS["unix"], 750.0)
self.assertEqual(benchmark_runtime.IMPORT_P95_BUDGETS_MS["macos"], 750.0)
self.assertEqual(benchmark_runtime.IMPORT_P95_BUDGETS_MS["windows"], 1_000.0)
self.assertEqual(benchmark_runtime.IMPORT_P95_BUDGETS_MS["wsl"], 1_000.0)
Loading