abench 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. abench-0.1.0/.github/workflows/ci.yml +69 -0
  2. abench-0.1.0/.github/workflows/publish.yml +61 -0
  3. abench-0.1.0/.pre-commit-config.yaml +13 -0
  4. abench-0.1.0/LICENSE +29 -0
  5. abench-0.1.0/MANIFEST.in +4 -0
  6. abench-0.1.0/PKG-INFO +381 -0
  7. abench-0.1.0/README.md +351 -0
  8. abench-0.1.0/RELEASING.md +52 -0
  9. abench-0.1.0/examples/sandag-chunked.yaml +33 -0
  10. abench-0.1.0/pyproject.toml +54 -0
  11. abench-0.1.0/setup.cfg +4 -0
  12. abench-0.1.0/src/abench/Dockerfile +10 -0
  13. abench-0.1.0/src/abench/__init__.py +3 -0
  14. abench-0.1.0/src/abench/__main__.py +3 -0
  15. abench-0.1.0/src/abench/attempts.py +66 -0
  16. abench-0.1.0/src/abench/cli.py +563 -0
  17. abench-0.1.0/src/abench/common.py +22 -0
  18. abench-0.1.0/src/abench/experiments.py +269 -0
  19. abench-0.1.0/src/abench/failures.py +103 -0
  20. abench-0.1.0/src/abench/flow_cache.py +65 -0
  21. abench-0.1.0/src/abench/profiles/mtc.yaml +46 -0
  22. abench-0.1.0/src/abench/profiles/sandag.yaml +65 -0
  23. abench-0.1.0/src/abench/profiles.py +139 -0
  24. abench-0.1.0/src/abench/report.py +483 -0
  25. abench-0.1.0/src/abench/runtime/__init__.py +1 -0
  26. abench-0.1.0/src/abench/runtime/build_sources.py +109 -0
  27. abench-0.1.0/src/abench/runtime/cache_identity.py +37 -0
  28. abench-0.1.0/src/abench/runtime/instrumentation.py +79 -0
  29. abench-0.1.0/src/abench/runtime/worker.py +318 -0
  30. abench-0.1.0/src/abench/sources.py +93 -0
  31. abench-0.1.0/src/abench.egg-info/PKG-INFO +381 -0
  32. abench-0.1.0/src/abench.egg-info/SOURCES.txt +48 -0
  33. abench-0.1.0/src/abench.egg-info/dependency_links.txt +1 -0
  34. abench-0.1.0/src/abench.egg-info/entry_points.txt +2 -0
  35. abench-0.1.0/src/abench.egg-info/requires.txt +9 -0
  36. abench-0.1.0/src/abench.egg-info/top_level.txt +1 -0
  37. abench-0.1.0/tests/fixtures/tiny/benchmark.yaml +20 -0
  38. abench-0.1.0/tests/fixtures/tiny/configs/settings.yaml +15 -0
  39. abench-0.1.0/tests/fixtures/tiny/data/households.csv +5 -0
  40. abench-0.1.0/tests/fixtures/tiny/tiny_extension.py +76 -0
  41. abench-0.1.0/tests/requirements.txt +6 -0
  42. abench-0.1.0/tests/test_attempts.py +84 -0
  43. abench-0.1.0/tests/test_builder.py +82 -0
  44. abench-0.1.0/tests/test_docker.py +156 -0
  45. abench-0.1.0/tests/test_experiments.py +181 -0
  46. abench-0.1.0/tests/test_failure_diagnostics.py +109 -0
  47. abench-0.1.0/tests/test_flow_cache.py +98 -0
  48. abench-0.1.0/tests/test_measurement.py +364 -0
  49. abench-0.1.0/tests/test_profiles_sources.py +191 -0
  50. abench-0.1.0/tests/test_warmup.py +74 -0
@@ -0,0 +1,69 @@
1
+ name: Tests
2
+ on:
3
+ push:
4
+ pull_request:
5
+ workflow_dispatch:
6
+ workflow_call:
7
+ permissions:
8
+ contents: read
9
+ concurrency:
10
+ group: tests-${{ github.workflow }}-${{ github.ref }}
11
+ cancel-in-progress: true
12
+ jobs:
13
+ unit:
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ python: ['3.10', '3.11', '3.12']
19
+ timeout-minutes: 20
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ - uses: actions/setup-python@v5
23
+ with:
24
+ python-version: ${{ matrix.python }}
25
+ cache: pip
26
+ - uses: actions/setup-node@v4
27
+ with:
28
+ node-version: '22'
29
+ - run: python -m pip install '.[test]' -r tests/requirements.txt
30
+ - run: ruff check . && ruff format --check .
31
+ - run: python -m pytest -m 'not docker' -q
32
+ - run: python -m build
33
+ - name: Verify installed wheel and packaged resources
34
+ run: |
35
+ python -m venv /tmp/abench-wheel
36
+ /tmp/abench-wheel/bin/pip install dist/*.whl
37
+ cd /tmp
38
+ /tmp/abench-wheel/bin/abench --help
39
+ /tmp/abench-wheel/bin/python -c "from pathlib import Path; import abench; p=Path(abench.__file__).parent; assert (p/'Dockerfile').is_file(); assert (p/'profiles/mtc.yaml').is_file(); assert (p/'runtime/build_sources.py').is_file()"
40
+ docker:
41
+ runs-on: ubuntu-latest
42
+ timeout-minutes: 30
43
+ steps:
44
+ - uses: actions/checkout@v4
45
+ - uses: actions/setup-python@v5
46
+ with:
47
+ python-version: '3.11'
48
+ cache: pip
49
+ - run: python -m pip install . pytest
50
+ - name: Build exact sources and exercise serial and multiprocess runs
51
+ env:
52
+ ABENCH_DOCKER_TESTS: '1'
53
+ run: |
54
+ mkdir -p experiments
55
+ python -m pytest tests/test_docker.py -v --basetemp=experiments/ci
56
+ - name: Retain reports and diagnostics
57
+ if: always()
58
+ uses: actions/upload-artifact@v4
59
+ with:
60
+ name: docker-experiments
61
+ path: |
62
+ experiments/ci/**/*.html
63
+ experiments/ci/**/*.json
64
+ experiments/ci/**/*.jsonl
65
+ experiments/ci/**/*.txt
66
+ experiments/ci/**/*.log
67
+ experiments/ci/**/*.csv
68
+ experiments/ci/**/*.yaml
69
+ if-no-files-found: ignore
@@ -0,0 +1,61 @@
1
+ name: Publish to PyPI
2
+ on:
3
+ release:
4
+ types: [published]
5
+ permissions:
6
+ contents: read
7
+ concurrency:
8
+ group: pypi-${{ github.event.release.tag_name }}
9
+ cancel-in-progress: false
10
+ jobs:
11
+ tests:
12
+ uses: ./.github/workflows/ci.yml
13
+ build:
14
+ needs: tests
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: '3.11'
21
+ - uses: astral-sh/setup-uv@v6
22
+ - run: python -m pip install build twine
23
+ # Build the wheel from the sdist, so both published formats are exercised.
24
+ - run: python -m build
25
+ - run: python -m twine check --strict dist/*
26
+ - run: python -m pip install dist/*.whl
27
+ - name: Match release tag to package version
28
+ env:
29
+ RELEASE_TAG: ${{ github.event.release.tag_name }}
30
+ run: |
31
+ python - <<'PY'
32
+ import os
33
+ from importlib.metadata import version
34
+ expected = 'v' + version('abench')
35
+ if os.environ['RELEASE_TAG'] != expected:
36
+ raise SystemExit(f'Release tag must be {expected}')
37
+ PY
38
+ - name: Smoke test isolated uvx installation
39
+ run: |
40
+ uvx --from "$PWD"/dist/abench-*.whl abench --version
41
+ uvx --from "$PWD"/dist/abench-*.whl abench --help
42
+ - uses: actions/upload-artifact@v4
43
+ with:
44
+ name: python-distributions
45
+ path: dist/*
46
+ if-no-files-found: error
47
+ publish:
48
+ needs: build
49
+ runs-on: ubuntu-latest
50
+ environment:
51
+ name: pypi
52
+ url: https://pypi.org/p/abench
53
+ permissions:
54
+ id-token: write
55
+ steps:
56
+ - uses: actions/download-artifact@v4
57
+ with:
58
+ name: python-distributions
59
+ path: dist/
60
+ - name: Publish distributions using Trusted Publishing
61
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,13 @@
1
+ repos:
2
+ - repo: local
3
+ hooks:
4
+ - id: ruff-check
5
+ name: Ruff check
6
+ entry: ruff check
7
+ language: system
8
+ types: [python]
9
+ - id: ruff-format
10
+ name: Ruff format
11
+ entry: ruff format --check
12
+ language: system
13
+ types: [python]
abench-0.1.0/LICENSE ADDED
@@ -0,0 +1,29 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, ActivitySim
4
+ Copyright (c) 2024, ActivitySim
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ 3. Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,4 @@
1
+ include LICENSE README.md RELEASING.md .pre-commit-config.yaml
2
+ recursive-include tests *.py *.yaml *.csv *.txt
3
+ recursive-include .github *.yml
4
+ recursive-include examples *.yaml
abench-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,381 @@
1
+ Metadata-Version: 2.4
2
+ Name: abench
3
+ Version: 0.1.0
4
+ Summary: Reproducible ActivitySim runtime and memory benchmarks in Linux containers
5
+ License-Expression: BSD-3-Clause
6
+ Project-URL: Homepage, https://github.com/ActivitySim/abench
7
+ Project-URL: Documentation, https://github.com/ActivitySim/abench#readme
8
+ Project-URL: Repository, https://github.com/ActivitySim/abench
9
+ Project-URL: Issues, https://github.com/ActivitySim/abench/issues
10
+ Keywords: activitysim,benchmark,transportation,memory,sharrow
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Operating System :: MacOS
14
+ Classifier: Operating System :: POSIX :: Linux
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Topic :: System :: Benchmark
18
+ Requires-Python: >=3.10
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: PyYAML>=6
22
+ Provides-Extra: test
23
+ Requires-Dist: pytest>=8; extra == "test"
24
+ Requires-Dist: pandas<3; extra == "test"
25
+ Requires-Dist: pyarrow; extra == "test"
26
+ Requires-Dist: numba; extra == "test"
27
+ Requires-Dist: ruff; extra == "test"
28
+ Requires-Dist: build; extra == "test"
29
+ Dynamic: license-file
30
+
31
+ # abench
32
+
33
+ Run reproducible ActivitySim runtime and memory experiments in Linux Docker,
34
+ from macOS or Linux. One runner supports MTC, SANDAG ABM3, and other models through
35
+ small YAML profiles. ActivitySim itself does not need to be installed on the host.
36
+
37
+ With [uv](https://docs.astral.sh/uv/), run without managing a Python environment:
38
+
39
+ ```bash
40
+ uvx abench --help
41
+ uvx abench experiments.yaml
42
+ ```
43
+
44
+ For a specific release use `uvx abench@0.1.0 experiments.yaml`; use
45
+ `uvx abench@latest` to refresh to the latest release. Docker and model data must
46
+ still be available locally. macOS and Linux hosts are supported.
47
+
48
+ Alternatively, install with pip:
49
+
50
+ ```bash
51
+ python -m pip install abench
52
+ abench run --model-dir /path/to/sandag-abm3-example --profile sandag \
53
+ --source activitysim=ActivitySim/activitysim@<full-40-character-SHA> \
54
+ --source sharrow=ActivitySim/sharrow@<full-40-character-SHA> \
55
+ --multiprocess --processes 4 --sharrow --households 28365 \
56
+ --memory 32g --shm-size 8g --output-dir /path/to/experiments/sandag
57
+ ```
58
+
59
+ Use `--profile mtc` for MTC; both profiles ship with the package. SANDAG defaults
60
+ to its small `benchmarking-data`, **not full-scale skims**. MTC defaults to
61
+ `data_full`. `--data-dir` overrides either. Model directories need not be Git
62
+ repositories; Git revision/status are recorded where available and model files
63
+ are always snapshotted. Existing example scripts and normal configs are untouched.
64
+
65
+ The host needs Python 3.10+, PyYAML (installed with abench), and a Linux Docker
66
+ engine with cgroup v2 and `memory.peak`. Docker Desktop must have enough VM RAM
67
+ for the chosen memory limit plus VM overhead. The default container is Debian
68
+ Bookworm/Python 3.11. Current instrumentation requires ActivitySim's
69
+ `workflow.State` API (1.4-era or newer); arbitrary historical revisions are not
70
+ promised to work. Build/runtime failures retain diagnostics and a failure report.
71
+
72
+ ## Named experiment files
73
+
74
+ Write common options once and override only what differs between runs:
75
+
76
+ ```yaml
77
+ schema_version: 1
78
+ vars:
79
+ households: 28365
80
+ warmup_households: 5000
81
+ model: /path/to/sandag-abm3-example
82
+ output_root: ./results/sandag-${timestamp}
83
+ defaults:
84
+ model_dir: ${model}
85
+ profile: sandag
86
+ data_dir: ${model}/benchmarking-data
87
+ config_overlay: ["${model}/configs_explicit_chunk"]
88
+ multiprocess: true
89
+ processes: 4
90
+ sharrow: true
91
+ households: ${households}
92
+ warmup_households: ${warmup_households}
93
+ memory: 80g
94
+ shm_size: 8g
95
+ sources:
96
+ - sharrow=ActivitySim/sharrow@fc175b27d8e0c5d202721c67d96b050e6117b235
97
+ runs:
98
+ main:
99
+ sources:
100
+ - activitysim=ActivitySim/activitysim@5c6fae24a91a57a2d6dfc2e1dbe062a61d94545a
101
+ pr1110:
102
+ sources:
103
+ - activitysim=ActivitySim/activitysim@51e298a84276813946e1d623c9a5785e078e022f
104
+ ```
105
+
106
+ Save it as `sandag.yaml`, then run:
107
+
108
+ ```bash
109
+ abench sandag.yaml
110
+ # Or check all runs without building images or running models:
111
+ abench validate sandag.yaml
112
+ ```
113
+
114
+ A ready-to-use [SANDAG chunked suite](examples/sandag-chunked.yaml) is included
115
+ in the repository. Its paths assume abench and the SANDAG repository are siblings.
116
+ The pinned `main` revision is the one used in the earlier trials, not a moving
117
+ branch reference.
118
+
119
+ - `defaults` accepts CLI options using underscores (`shm_size`, `config_overlay`,
120
+ etc.). Use `multiprocess: false` for serial execution and `sharrow: false` to
121
+ disable Sharrow. `sources` accepts the same strings/mappings as model profiles.
122
+ - `runs` is an ordered mapping of names to overrides. Each run inherits defaults;
123
+ ordinary values and lists are replaced. **Sources merge by normalized package
124
+ name**, so changing ActivitySim does not discard the shared Sharrow pin.
125
+ - `${name}` substitutes a reusable scalar from `vars`; terms can reference other
126
+ terms. A whole-value reference preserves its type, including numbers/booleans.
127
+ Undefined references and cycles are errors. No shell or environment expansion
128
+ is performed. `${timestamp}` is a built-in UTC launch identifier shared by all
129
+ runs, with microseconds to avoid reusing output directories.
130
+ - All explicit paths in the suite are relative to the YAML file, independent of
131
+ the terminal's current directory. This includes overlays and custom profile
132
+ paths. Built-in `mtc`/`sandag` profile names retain their meaning. When omitted,
133
+ `model_dir` defaults to the YAML file's directory; the model profile still
134
+ supplies its usual default data/config paths.
135
+ - The suite owns output locations: `output_root/<run-name>/`. Set `output_root`
136
+ once instead of `output_dir` in each run. Existing roots are rejected.
137
+ - All runs are preflighted before the first starts, then run sequentially in file
138
+ order. Failure stops the suite and retains partial results. The combined report
139
+ is `output_root/comparison.html`; individual runs retain their own reports.
140
+ `experiments.yaml` and `suite.json` record the original file and expanded plan.
141
+ - File invocations do not accept additional CLI overrides. Edit `defaults` or the
142
+ relevant run to keep the file a complete description of the experiment.
143
+
144
+ This experiment file describes **which tests to run**. A model profile such as
145
+ `benchmark.yaml` describes **how to configure a model**, and remains reusable
146
+ across suites.
147
+
148
+ ## Run controls
149
+
150
+ - `--single-process` (default), or `--multiprocess --processes N`. The count applies
151
+ to every sliced stage; coordinators are additional processes.
152
+ - `--sharrow` (default) or `--no-sharrow`. Sharrow enabled requires its source pin.
153
+ - `--households N` (default 1,000); zero uses the original full input population.
154
+ abench never replicates households. Positive samples must match realized output.
155
+ - `--config-overlay configs_explicit_chunk` adds config directories in listed
156
+ priority order. Relative overlay paths are relative to the model directory.
157
+ - `--memory 16g`, `--shm-size 8g`, `--interval 0.5`, and optional `--platform`.
158
+ - `--output-dir` must be new. `--label` names an experiment, and `--compare` accepts
159
+ earlier experiment directories. Compatible compiled flows are reused automatically;
160
+ the serial warmup still runs.
161
+
162
+ `abench validate` accepts the same experiment arguments without `--output-dir`.
163
+ It checks the profile, required inputs, CSV population size, source pin syntax,
164
+ and Docker capabilities without building an image or running the model. It does
165
+ not prove Git commit availability, package compatibility, or skim consistency;
166
+ those are checked by the build and model run.
167
+
168
+ ## Any dependency from GitHub source
169
+
170
+ Repeat `--source` for any Python distribution, including add-on extensions:
171
+
172
+ ```bash
173
+ --source 'my-addon[fast]=ExampleOrg/model-addon@<SHA>#subdirectory=python/addon'
174
+ ```
175
+
176
+ The left side is the **distribution name** (which can differ from its import
177
+ module). Each source uses an exact full SHA and an `organization/repository` name.
178
+ Extras and a repository subdirectory are optional. Profiles can declare the same
179
+ entries as strings or mappings:
180
+
181
+ ```yaml
182
+ sources:
183
+ - name: my-addon
184
+ repository: ExampleOrg/model-addon
185
+ commit: '0123456789abcdef0123456789abcdef01234567'
186
+ extras: [fast]
187
+ subdirectory: python/addon
188
+ ```
189
+
190
+ CLI sources override profile sources by normalized distribution name. Duplicate
191
+ CLI entries are errors. `--activitysim-commit` and `--sharrow-commit` remain aliases
192
+ for the official repositories; conflicting alias/source declarations are errors.
193
+
194
+ Inside Docker, abench verifies each checkout's Git object, builds a wheel, checks
195
+ its distribution name, then installs all source wheels together with other
196
+ requirements. It runs `pip check` and verifies installed wheel identities. Exact
197
+ source commits, resolved versions, and the full dependency environment are saved.
198
+ All source dependencies must agree: conflicting requirements fail the build.
199
+
200
+ Use profile `requirements` for additional registry requirements and `constraints`
201
+ for resolver bounds or exact transitive pins. Profiles may select `python_image`
202
+ (a compatible Debian-based image, optionally pinned by digest). The default image
203
+ includes a compiler and HDF5 headers. Packages requiring other system libraries
204
+ can use a prebuilt compatible base image. Private GitHub authentication and custom
205
+ OS provisioning are outside the initial interface.
206
+
207
+ Source pins do not freeze unpinned transitive/build dependencies or base images.
208
+ Retain images and dependency manifests for strict reproduction. Build isolation
209
+ may fetch build requirements; constraints currently govern the final environment,
210
+ not those isolated build environments.
211
+
212
+ ## Add another model
213
+
214
+ Create `benchmark.yaml` in its model directory, then use `--model-dir`:
215
+
216
+ ```yaml
217
+ schema_version: 1
218
+ name: My regional model
219
+ configs: [configs]
220
+ mp_configs: [configs_mp]
221
+ snapshot: [configs, configs_mp, extensions]
222
+ extensions: [extensions]
223
+ data_dir: data
224
+ required_inputs:
225
+ - [households.csv, households.parquet]
226
+ - persons.csv
227
+ - land_use.csv
228
+ - skims.omx
229
+ settings:
230
+ use_shadow_pricing: false
231
+ rng_base_seed: 0
232
+ input_tables:
233
+ households: {}
234
+ persons: {}
235
+ land_use:
236
+ totals: [TOTPOP, TOTHH, TOTEMP]
237
+ zone_columns: [TAZ]
238
+ output_tables:
239
+ households: {}
240
+ persons: {}
241
+ tours: {}
242
+ trips:
243
+ categories: [trip_mode, primary_purpose]
244
+ ```
245
+
246
+ Paths in a profile are relative to the model directory (except `data_dir`, which
247
+ may be absolute). `configs` and `mp_configs` are ordered, highest priority first.
248
+ `snapshot` must cover config files, local extension modules, and adapter modules;
249
+ entries must not overlap or contain directory symlinks. Data is mounted read-only
250
+ and should not change during a run. Profiles are trusted model code/configuration.
251
+
252
+ Settings precedence, lowest to highest: **normal model configs → profile settings
253
+ → user overlays → required CLI controls** (sample, SP/MP, worker counts, Sharrow,
254
+ and fail-fast). Generated inheriting profile configs preserve this ordering when
255
+ ActivitySim reconstructs worker settings. Component overlays remain independent.
256
+
257
+ Optional profile fields:
258
+
259
+ | Field | Purpose |
260
+ |---|---|
261
+ | `models_from`, `exclude_models` | Take a YAML `models` list and explicitly omit diagnostic steps. Otherwise use normal settings. |
262
+ | `mp_settings` | Read `multiprocess_steps` from a separate YAML file. |
263
+ | `extensions` | Import modules through ActivitySim's registration mechanism, including spawned workers. Installing a package alone does not register its components. |
264
+ | `adapter: module:function` | Optional `function(state, spec, phase)` initialization hook, called once in the model parent before execution. Use `state.import_extensions` for worker setup; parent-only mutations are not automatically worker initialization. |
265
+ | `input_tables`, `output_tables` | Logical table names mapped to summary options: `file` (stem), `totals`, `categories`, and `zone_columns` for land use. CSV and Parquet are supported. Use logical `households` for sample validation. |
266
+ | `output_prefix` | Default `final_`; applied to output file stems. |
267
+ | `household_table` | Default `households.csv`, used for early CSV sample validation. Parquet samples are checked after execution. |
268
+ | `zone_label` | Display label for land-use rows, such as zones or MAZs. |
269
+
270
+ For specialized data formats, an adapter can arrange compatible CSV/Parquet
271
+ summary outputs. The initial generic reader does not interpret arbitrary binary
272
+ model outputs.
273
+
274
+ ## Measurement and reports
275
+
276
+ Sharrow runs first execute the model in a separate **single-process** warmup,
277
+ using **min(target households, 5000)** households by default. For `--households 0`,
278
+ the target is the full available population, so warmup uses at most 5000 of those
279
+ households. Set `--warmup-households N` (or `warmup_households: N` in experiment
280
+ YAML) to change this positive cap. Warmup always uses one process; measured runs
281
+ retain their requested sample and worker count. Model config directories, seed,
282
+ chunk overlays, and flow cache path are retained from the target experiment.
283
+
284
+ Compiled flows are automatically reused across runs and suites, including changes
285
+ in ActivitySim revisions, sample sizes, process counts, and model configs. The
286
+ persistent host cache defaults to `~/.cache/abench/flows`. Change it with
287
+ `--flow-cache-dir PATH` (`flow_cache_dir` in YAML), or disable automatic reads and
288
+ writes with `--no-reuse-flows` (`reuse_flows: false`). `--cache-from` remains an
289
+ explicit seed option with its existing stricter dependency checks.
290
+
291
+ Compatibility uses the **installed** Sharrow, Numba, llvmlite, and NumPy versions,
292
+ plus their source repository/commit identities when applicable, Python version,
293
+ and container architecture/CPU features. ActivitySim and model settings are
294
+ excluded from this key: Sharrow identifies generated flows by their contents,
295
+ and Numba checks cached signatures. Changed flows can compile during warmup.
296
+ An existing cache does **not** guarantee that warmup will need no compilation.
297
+
298
+ Each experiment receives a private copy with source timestamps preserved. Warmup
299
+ always runs, and successful warmups atomically update the persistent cache before
300
+ measurement starts. Compatible simultaneous experiments wait for each other to avoid losing
301
+ compiled signatures when attempts update Numba cache indexes. Only `cache/flows`
302
+ is shared, never model data, outputs, or shared-memory artifacts. Cache identity
303
+ and reuse counts are recorded in `flow-cache-identity.json` and `experiment.json`.
304
+ The persistent cache can be deleted between runs to reclaim disk space; older
305
+ experiments created before this feature are not automatically imported.
306
+
307
+ A smaller serial warmup may not exercise every flow/type signature needed by the
308
+ measured run. Each measured attempt therefore records flow compilation and allows
309
+ it to finish. If compilation occurred, the completed attempt becomes **cache
310
+ preparation**, and none of its runtime or memory results qualify as benchmark
311
+ results. Its diagnostics and outputs are retained under `attempts/attempt-001`,
312
+ `attempts/attempt-002`, etc. Newly compiled flows are published to the shared cache.
313
+
314
+ The model then restarts in a fresh container with fresh outputs and model caches,
315
+ using the same settings and expanded flow cache. Only an attempt with **zero flow
316
+ compilations** is accepted. All attempts keep permanent directories under
317
+ `attempts/`; `measured/` links to the accepted attempt. By default abench allows
318
+ **two additional attempts** (three total). Set `--cache-retries N` or
319
+ `cache_retries: N` in YAML; zero allows no retries. If compilation persists, the
320
+ experiment fails with the final attempt's diagnostics retained. Ordinary model
321
+ errors, OOMs, and output validation failures stop immediately and are never
322
+ retried as cache preparation.
323
+
324
+ The report and `experiment.json` include attempt history. Each attempt retains
325
+ `cache-miss-details-*.jsonl`, its settings, component timings, and memory samples.
326
+ Ordinary non-flow compilation and disk-cache loading remain included in accepted
327
+ measurements. Flow tracking uses private Numba internals and is covered by real
328
+ compilation, cache-hit, and Docker retry tests.
329
+
330
+ Memory is the whole-container cgroup v2 charge, counting shared pages once.
331
+ Blue is `memory.current` (including file cache, shared memory, and kernel costs).
332
+ Green dashed is `anon + shmem`, a subset excluding ordinary file cache and kernel
333
+ costs. Never add the lines. Swap is recorded separately and disabled by equal
334
+ memory/memory+swap limits. `/dev/shm` capacity is within that limit.
335
+
336
+ Component runtimes show worker mean, population SD, count, and maximum. Worker SD
337
+ is imbalance, not confidence across repeated trials. The component dropdown
338
+ highlights each worker's actual window; overlaps darken and gaps remain clear.
339
+ Overall elapsed includes startup, coordination, and checkpoint writes between
340
+ components. Kernel peak includes startup; warmup and post-run summaries are
341
+ excluded. Shared VM page-cache ownership can influence container charges: this
342
+ is not a cold-input I/O benchmark.
343
+
344
+ ```bash
345
+ abench report --compare /path/to/run-a /path/to/run-b \
346
+ --output-dir /path/to/comparison.html
347
+ ```
348
+
349
+ Reports are offline HTML/SVG/JavaScript plus normalized JSON. They retain fastest
350
+ successful component highlighting and use common memory axes. Existing MTC and
351
+ SANDAG schema-1 experiments remain readable, including approximate legacy timing
352
+ windows where only completion logs exist. New experiments use schema 2 and include
353
+ source manifests, resolved profile/settings, model and harness snapshots, file
354
+ hashes, Docker details, and source installation provenance. Input file size/mtime
355
+ records are provenance hints, not content hashes of large skims.
356
+
357
+ ## Development and CI
358
+
359
+ ```bash
360
+ python -m pip install -e '.[test]' -r tests/requirements.txt
361
+ python -m pytest -m 'not docker'
362
+ pre-commit run --all-files
363
+ python -m build
364
+ ABENCH_DOCKER_TESTS=1 python -m pytest tests/test_docker.py -v
365
+ ```
366
+
367
+ Install Node.js to exercise the offline chart selector test. GitHub Actions runs
368
+ unit tests on Python 3.10–3.12, lint/format checks, wheel packaging checks, and Linux
369
+ Docker integration. The Docker tests build pinned ActivitySim/Sharrow sources and
370
+ run a four-household extension workflow in serial and multiprocess modes, checking
371
+ warmup, generated-code cache reuse, per-worker timings, merged outputs, memory,
372
+ and reports. They do not require either example repository or large datasets.
373
+
374
+ Adapted from the MTC and SANDAG benchmark harnesses developed in this workspace.
375
+ The original measurement approach was informed by WSP's Lighthouse production
376
+ benchmark. See LICENSE for the retained BSD license.
377
+
378
+ ## Releases
379
+
380
+ See [RELEASING.md](https://github.com/ActivitySim/abench/blob/main/RELEASING.md)
381
+ for Trusted Publishing setup and release instructions.