diff --git a/CHANGELOG.md b/CHANGELOG.md index fe37dfc..01c8b8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ ## Unreleased +### Configurable benchmark timeout per runner + +Runners can now set a `timeout_minutes` field in `bench_runner.toml` to +override the maximum runtime for benchmark jobs. If unset, the per-OS default +in the workflow template applies (Linux: 1440, others: GitHub default). + +```toml +[runners.example] +os = "linux" +arch = "x86_64" +hostname = "example" +timeout_minutes = 210 +``` + ### Bugfixes #### Use PGO on weekly builds diff --git a/README.md b/README.md index 5d0a817..25b804d 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,12 @@ You may limit the number of cores used to build Python with the `use_cores` opti use_cores = 2 ``` +You may set a maximum runtime for benchmark jobs on a runner with `timeout_minutes`. If unset, the per-OS default in the workflow template applies (Linux: 1440, others: the GitHub default). + +``` +timeout_minutes = 210 +``` + ### Try a benchmarking run There are instructions for running a benchmarking action already in the `README.md` of your repo. Look there and give it a try! diff --git a/bench_runner/runners.py b/bench_runner/runners.py index 826a43f..b218b0c 100644 --- a/bench_runner/runners.py +++ b/bench_runner/runners.py @@ -46,6 +46,10 @@ class Runner: # The number of cores to use to compile CPython. If not provided, `make -j` # will be used. use_cores: int | None = None + # Maximum runtime for benchmark jobs on this runner, in minutes. If unset, + # the per-OS default in the workflow template applies (Linux: 1440, others: + # GitHub default). + timeout_minutes: int | None = None def __post_init__(self): if self.github_runner_name is None: diff --git a/bench_runner/scripts/install.py b/bench_runner/scripts/install.py index 3e78e7f..2eaf6fc 100644 --- a/bench_runner/scripts/install.py +++ b/bench_runner/scripts/install.py @@ -23,7 +23,6 @@ from bench_runner import runners from bench_runner.util import PathLike - ROOT_PATH = Path() TEMPLATE_PATH = Path(__file__).parents[1] / "templates" WORKFLOW_PATH = Path() / ".github" / "workflows" @@ -178,6 +177,13 @@ def generate__benchmark(src: Any) -> Any: runner_template["runs-on"].append(runner.github_runner_name) + if runner.timeout_minutes is not None: + # Insert right after runs-on for readable YAML, regardless of + # whether the per-OS skeleton already had a timeout-minutes key. + runner_template.pop("timeout-minutes", None) + idx = list(runner_template.keys()).index("runs-on") + 1 + runner_template.insert(idx, "timeout-minutes", runner.timeout_minutes) + machine_clauses = [ f"inputs.machine == '{runner.name}'", "inputs.machine == '__really_all'", diff --git a/tests/data/bench_runner.toml b/tests/data/bench_runner.toml index aeb00e4..0d6552a 100644 --- a/tests/data/bench_runner.toml +++ b/tests/data/bench_runner.toml @@ -7,6 +7,7 @@ os = "linux" arch = "x86_64" hostname = "pyperf" plot = { name = "Linux", color = "C0" } +timeout_minutes = 210 [longitudinal_plot] subplots = [ diff --git a/tests/test_config.py b/tests/test_config.py index 10cbfb9..5988b99 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -4,7 +4,6 @@ from bench_runner import runners - DATA_PATH = Path(__file__).parent / "data" @@ -16,3 +15,9 @@ def test_get_runner_for_hostname(monkeypatch): assert runner.os == "linux" assert runner.arch == "x86_64" assert runner.hostname == "pyperf" + assert runner.timeout_minutes == 210 + + +def test_runner_timeout_minutes_default(): + runner = runners.Runner(nickname="x", os="linux", arch="x86_64", hostname="x") + assert runner.timeout_minutes is None