benchset 0.0.2__tar.gz → 0.0.4__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.
- {benchset-0.0.2 → benchset-0.0.4}/Cargo.lock +1 -1
- {benchset-0.0.2 → benchset-0.0.4}/Cargo.toml +2 -1
- {benchset-0.0.2 → benchset-0.0.4}/MANIFEST.in +2 -1
- {benchset-0.0.2 → benchset-0.0.4}/PKG-INFO +245 -32
- {benchset-0.0.2 → benchset-0.0.4}/Package.swift +2 -2
- {benchset-0.0.2 → benchset-0.0.4}/README.md +244 -31
- {benchset-0.0.2 → benchset-0.0.4}/Sources/Benchset/Benchset.swift +102 -8
- {benchset-0.0.2 → benchset-0.0.4}/benchset/__init__.py +7 -0
- {benchset-0.0.2 → benchset-0.0.4}/benchset/_native.py +70 -10
- {benchset-0.0.2 → benchset-0.0.4}/benchset/api.py +69 -39
- benchset-0.0.4/benchset/cli.py +270 -0
- {benchset-0.0.2 → benchset-0.0.4}/benchset/models.py +18 -0
- benchset-0.0.4/benchset/reference.py +74 -0
- {benchset-0.0.2 → benchset-0.0.4}/benchset.egg-info/PKG-INFO +245 -32
- {benchset-0.0.2 → benchset-0.0.4}/benchset.egg-info/SOURCES.txt +20 -1
- benchset-0.0.4/examples/native/c.c +40 -0
- benchset-0.0.4/examples/native/rust.rs +53 -0
- benchset-0.0.4/examples/native/swift.swift +12 -0
- benchset-0.0.4/include/benchset.h +109 -0
- benchset-0.0.4/native/reference-calibration.json +47 -0
- {benchset-0.0.2 → benchset-0.0.4}/native/src/ffi.rs +212 -12
- benchset-0.0.4/native/src/ffi_reference_tests.rs +872 -0
- {benchset-0.0.2 → benchset-0.0.4}/native/src/ffi_tests.rs +167 -57
- {benchset-0.0.2 → benchset-0.0.4}/native/src/kernel_tests.rs +52 -0
- {benchset-0.0.2 → benchset-0.0.4}/native/src/lib.rs +73 -43
- benchset-0.0.4/native/src/reference.rs +77 -0
- benchset-0.0.4/native/src/reference_tests.rs +312 -0
- {benchset-0.0.2 → benchset-0.0.4}/native/src/runtime_tests.rs +382 -28
- {benchset-0.0.2 → benchset-0.0.4}/pyproject.toml +2 -2
- {benchset-0.0.2 → benchset-0.0.4}/scripts/build_native.py +6 -0
- {benchset-0.0.2 → benchset-0.0.4}/scripts/check_native_coverage.py +7 -0
- benchset-0.0.4/scripts/check_source_install.py +173 -0
- {benchset-0.0.2 → benchset-0.0.4}/scripts/package_native.py +12 -1
- {benchset-0.0.2 → benchset-0.0.4}/scripts/release.py +33 -24
- benchset-0.0.4/scripts/version.py +109 -0
- {benchset-0.0.2 → benchset-0.0.4}/setup.py +19 -6
- benchset-0.0.4/tests/__init__.py +0 -0
- benchset-0.0.4/tests/helpers.py +35 -0
- {benchset-0.0.2 → benchset-0.0.4}/tests/swift/BenchsetTests.swift +342 -30
- benchset-0.0.4/tests/swift/ReferenceTests.swift +311 -0
- {benchset-0.0.2 → benchset-0.0.4}/tests/test_benchset.py +52 -12
- benchset-0.0.4/tests/test_cli.py +862 -0
- {benchset-0.0.2 → benchset-0.0.4}/tests/test_errors.py +19 -1
- benchset-0.0.4/tests/test_reference.py +646 -0
- benchset-0.0.4/tests/test_reference_artifacts.py +777 -0
- benchset-0.0.4/tests/test_reference_native.py +139 -0
- {benchset-0.0.2 → benchset-0.0.4}/tests/test_release.py +128 -7
- {benchset-0.0.2 → benchset-0.0.4}/tests/test_resources.py +6 -2
- {benchset-0.0.2 → benchset-0.0.4}/tests/test_semantics.py +190 -26
- benchset-0.0.4/tests/test_signals.py +310 -0
- benchset-0.0.4/tests/test_version.py +178 -0
- benchset-0.0.4/tests/typing/__init__.py +1 -0
- benchset-0.0.4/tests/typing/reference_negative.py +15 -0
- benchset-0.0.4/tests/typing/reference_positive.py +46 -0
- benchset-0.0.4/tests/typing/test_reference_types.py +46 -0
- benchset-0.0.2/benchset/cli.py +0 -168
- benchset-0.0.2/examples/native/c.c +0 -26
- benchset-0.0.2/examples/native/rust.rs +0 -15
- benchset-0.0.2/examples/native/swift.swift +0 -5
- benchset-0.0.2/include/benchset.h +0 -64
- benchset-0.0.2/scripts/check_source_install.py +0 -44
- {benchset-0.0.2 → benchset-0.0.4}/LICENSE +0 -0
- {benchset-0.0.2 → benchset-0.0.4}/benchset/__main__.py +0 -0
- {benchset-0.0.2 → benchset-0.0.4}/benchset/py.typed +0 -0
- {benchset-0.0.2 → benchset-0.0.4}/benchset.egg-info/dependency_links.txt +0 -0
- {benchset-0.0.2 → benchset-0.0.4}/benchset.egg-info/entry_points.txt +0 -0
- {benchset-0.0.2 → benchset-0.0.4}/benchset.egg-info/requires.txt +0 -0
- {benchset-0.0.2 → benchset-0.0.4}/benchset.egg-info/top_level.txt +0 -0
- {benchset-0.0.2 → benchset-0.0.4}/include/module.modulemap +0 -0
- {benchset-0.0.2 → benchset-0.0.4}/native/src/kernel.rs +0 -0
- {benchset-0.0.2 → benchset-0.0.4}/rust-toolchain.toml +0 -0
- {benchset-0.0.2 → benchset-0.0.4}/scripts/__init__.py +0 -0
- {benchset-0.0.2 → benchset-0.0.4}/scripts/build_backend.py +0 -0
- {benchset-0.0.2 → benchset-0.0.4}/setup.cfg +0 -0
- {benchset-0.0.2 → benchset-0.0.4}/tests/test_build.py +0 -0
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
include setup.py
|
|
2
2
|
include Cargo.toml Cargo.lock rust-toolchain.toml LICENSE README.md
|
|
3
3
|
recursive-include native *.rs
|
|
4
|
+
include native/reference-calibration.json
|
|
4
5
|
recursive-include include *.h *.modulemap
|
|
5
6
|
recursive-include scripts *.py
|
|
6
7
|
recursive-include examples *.c *.rs *.swift
|
|
7
8
|
include Package.swift
|
|
8
9
|
recursive-include Sources *.swift
|
|
9
|
-
recursive-include tests *.swift
|
|
10
|
+
recursive-include tests *.py *.swift
|
|
10
11
|
prune target
|
|
11
12
|
prune Artifacts
|
|
12
13
|
prune benchset/_native
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: benchset
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary: Sustained scalar CPU benchmarks with an embeddable Rust core
|
|
5
5
|
Author-email: Evgeniy Blinov <zheni-b@yandex.ru>
|
|
6
6
|
Project-URL: Source, https://github.com/mutating/benchset
|
|
@@ -41,7 +41,13 @@ needed by applications embedding the native library.
|
|
|
41
41
|
The initial suite contains **`single_core`** (one computational worker) and
|
|
42
42
|
**`multi_core`** (all available computational workers). Both execute the same
|
|
43
43
|
fixed mixed workload and return a score in **completed iterations per second**.
|
|
44
|
-
Higher is faster.
|
|
44
|
+
Higher is faster. Each completed result also includes a **Pi equivalent**:
|
|
45
|
+
its throughput divided by the same benchmark's sustained Raspberry Pi 5 score.
|
|
46
|
+
`0.5` means half the Pi's throughput, `1.0` equal throughput, and `2.0` twice
|
|
47
|
+
the Pi's throughput. The CLI prints both iterations/s and `Pi equivalent`.
|
|
48
|
+
|
|
49
|
+
This README describes the current source tree. For changes not yet published,
|
|
50
|
+
use `pip install .` or the local Rust/Swift dependencies described below.
|
|
45
51
|
|
|
46
52
|
## Install and run
|
|
47
53
|
|
|
@@ -67,14 +73,17 @@ these build tools.
|
|
|
67
73
|
|
|
68
74
|
| CLI option | Default | Meaning |
|
|
69
75
|
|---|---:|---|
|
|
70
|
-
| `--bench` | all | `single_core` or `multi_core`;
|
|
76
|
+
| `--bench` | all | `all`, `single_core` or `multi_core`; `all` runs both in this order |
|
|
71
77
|
| `--warmup` | 120 | Seconds of continuous workload excluded from the score; zero is allowed |
|
|
72
78
|
| `--duration` | 60 | Seconds of measurement after warmup; must be positive |
|
|
73
|
-
| `--help` | | Show
|
|
79
|
+
| `-h`, `--help` | | Show options, defaults, examples and Pi equivalent interpretation |
|
|
74
80
|
| `--version` | | Show the library/benchmark version |
|
|
75
81
|
|
|
76
82
|
`--bench` is the public spelling of the selector. CLI settings are read through
|
|
77
83
|
`skelet`; configuration files and environment settings are not used.
|
|
84
|
+
Options accept both `--duration 0.5` and `--duration=0.5`, in any order;
|
|
85
|
+
durations accept decimal and scientific notation. A supplied option requires
|
|
86
|
+
a value. Repeating an option uses its last value.
|
|
78
87
|
|
|
79
88
|
A default full suite takes approximately six minutes. Each benchmark has its
|
|
80
89
|
own warmup. Warmup transitions directly into measurement without stopping the
|
|
@@ -83,6 +92,25 @@ Completed result fields, including all measurement samples, are printed to
|
|
|
83
92
|
stdout. Failed/cancelled results go to stderr. Exit codes: 0 completed, 1
|
|
84
93
|
execution failure, 2 invalid CLI arguments, 130 interrupted/cancelled. The
|
|
85
94
|
suite stops after a failed or cancelled benchmark.
|
|
95
|
+
Each result is flushed immediately, including when stdout is redirected.
|
|
96
|
+
Progress fits the terminal width and is cleared before the result. Output
|
|
97
|
+
uses `× pi` and `—` when the stream supports them, with `x pi` and `-` as
|
|
98
|
+
fallbacks for restrictive encodings. A closed stdout pipe exits with code 1
|
|
99
|
+
without a traceback.
|
|
100
|
+
|
|
101
|
+
For example, a completed result at half the reference throughput includes
|
|
102
|
+
these lines (illustrative values; other fields and samples are omitted):
|
|
103
|
+
|
|
104
|
+
```text
|
|
105
|
+
Benchmark : single_core
|
|
106
|
+
Score : 23,615.614
|
|
107
|
+
Unit : iterations/s
|
|
108
|
+
Reference machine : Raspberry Pi 5 Model B Rev 1.0 (pi)
|
|
109
|
+
Pi equivalent : 0.5 × pi
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The multiplier uses the full-precision native score, before display rounding.
|
|
113
|
+
An unavailable multiplier is displayed as `—` (`-` in the fallback format).
|
|
86
114
|
|
|
87
115
|
## Python API
|
|
88
116
|
|
|
@@ -94,11 +122,12 @@ from benchset import run, run_all
|
|
|
94
122
|
|
|
95
123
|
result = run('single_core', warmup_seconds=120, measurement_seconds=60)
|
|
96
124
|
if result.success:
|
|
97
|
-
print(result.score, result.
|
|
125
|
+
print(f'{result.score} {result.unit}, {result.pi_equivalent} x {result.reference_machine.short_name}')
|
|
98
126
|
else:
|
|
99
127
|
print(result.status, result.reason)
|
|
100
128
|
|
|
101
129
|
results = run_all(warmup_seconds=120, measurement_seconds=60)
|
|
130
|
+
print(result.reference_run.started_at, result.reference_run.results)
|
|
102
131
|
```
|
|
103
132
|
|
|
104
133
|
For a GUI or cancellable task, run a reusable runner on a background thread:
|
|
@@ -126,12 +155,17 @@ iterations in that phase. Dispatch UI updates to the UI thread yourself and
|
|
|
126
155
|
return promptly. A Python callback exception cancels the workload and produces
|
|
127
156
|
a failed result; it does not propagate through C.
|
|
128
157
|
|
|
129
|
-
`BenchmarkRunner.cancel()` is thread-safe
|
|
130
|
-
|
|
158
|
+
`BenchmarkRunner.cancel()` is thread-safe and requests cancellation without
|
|
159
|
+
waiting for the active call to finish. After `run()` returns, all native workers
|
|
160
|
+
are joined and the runner can be reused. Concurrent
|
|
131
161
|
runs are rejected. The native core enforces one active run per loaded library
|
|
132
162
|
instance, including calls from separate Python runners. Separate OS processes
|
|
133
163
|
or separately linked copies of the library can still compete for CPU time.
|
|
134
164
|
|
|
165
|
+
With Python's default SIGINT handler, Ctrl+C during a main-thread call cancels
|
|
166
|
+
the native work and raises `KeyboardInterrupt` after cleanup. Custom signal
|
|
167
|
+
handlers are preserved.
|
|
168
|
+
|
|
135
169
|
## What one iteration does
|
|
136
170
|
|
|
137
171
|
This is a fixed scalar integer workload, not a prediction of arbitrary
|
|
@@ -193,6 +227,8 @@ The immutable Python result contains:
|
|
|
193
227
|
| `benchmark`, `version` | Name and benchmark/library version |
|
|
194
228
|
| `status`, `success`, `reason` | `completed`, `cancelled` or `failed`; explanation on failure |
|
|
195
229
|
| `score`, `unit` | Iterations/s; `score=None` unless completed |
|
|
230
|
+
| `pi_equivalent` | Double-precision `score / reference_score` for this benchmark; `None` unless completed |
|
|
231
|
+
| `reference_machine`, `reference_run` | Calibration machine and series, present for every result status |
|
|
196
232
|
| `workers` | Number of computational workers |
|
|
197
233
|
| `warmup_seconds`, `measurement_seconds` | Requested windows |
|
|
198
234
|
| `elapsed_seconds`, `iterations` | Actual measured wall time and completed work |
|
|
@@ -205,21 +241,124 @@ interval iterations and iterations/s. Variation is `None` with fewer than two
|
|
|
205
241
|
samples. It reports within-run variability, not repeat-to-repeat accuracy.
|
|
206
242
|
An unstable run retains its score and completed status; the consumer decides
|
|
207
243
|
whether to use it. Cancellation/failure can retain partial diagnostics but
|
|
208
|
-
never produces a usable score.
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
244
|
+
never produces a usable score or Pi equivalent. An unstable completed run
|
|
245
|
+
retains its Pi equivalent. Multi-core compares total measured throughput with
|
|
246
|
+
the multi-core reference; it does not normalize either score by worker count.
|
|
247
|
+
|
|
248
|
+
## The Pi reference
|
|
249
|
+
|
|
250
|
+
The immutable global machine record is `PI_REFERENCE_MACHINE` in Rust/Python
|
|
251
|
+
and `piReferenceMachine` in Swift. It describes **Raspberry Pi 5 Model B Rev
|
|
252
|
+
1.0**, abbreviated **`pi`**, with **Ubuntu Server 26.04 LTS**, **aarch64**, four
|
|
253
|
+
CPU cores and **8 GiB (8,589,934,592 bytes) of installed RAM**. Installed
|
|
254
|
+
capacity differs from the OS's usable `MemTotal` (8,317,272,064 bytes during
|
|
255
|
+
calibration). The metadata describes the reference machine, independently of
|
|
256
|
+
the device running the library.
|
|
257
|
+
|
|
258
|
+
The public names are:
|
|
259
|
+
|
|
260
|
+
| Interface | Result multiplier | Reference machine | Reference series |
|
|
261
|
+
|---|---|---|---|
|
|
262
|
+
| Python | `result.pi_equivalent: Optional[float]` | `result.reference_machine: ReferenceMachine` | `result.reference_run: ReferenceRun` |
|
|
263
|
+
| Rust | `result.pi_equivalent: Option<f64>` | `result.reference_machine: &'static ReferenceMachine` | `result.reference_run: &'static ReferenceRun` |
|
|
264
|
+
| Swift | `result.piEquivalent: Double?` | `result.referenceMachine: ReferenceMachine` | `result.referenceRun: ReferenceRun` |
|
|
265
|
+
| C / C++ V3 | `result.base.pi_equivalent`, when `result.base.has_pi_equivalent != 0` | `result.reference_machine` | `result.reference_run` + `benchset_reference_result` |
|
|
266
|
+
|
|
267
|
+
Every returned result carries these calibration records, including completed,
|
|
268
|
+
unstable, failed, cancelled, busy and validation-error results. They describe
|
|
269
|
+
the same fixed Pi reference for both workloads. Python fields default to the
|
|
270
|
+
existing globals (`result.reference_machine is PI_REFERENCE_MACHINE` and
|
|
271
|
+
`result.reference_run is PI_REFERENCE_RUN`); the new fields follow all previous
|
|
272
|
+
constructor arguments. `dataclasses.asdict(result)` includes both records as
|
|
273
|
+
nested data with numeric `started_at_unix_seconds`. Rust fields borrow the
|
|
274
|
+
public statics. Swift computed properties return the global structs with ordinary
|
|
275
|
+
value semantics. The globals
|
|
276
|
+
remain available without running a benchmark; C also retains its handle-free
|
|
277
|
+
`benchset_reference_machine` and `benchset_reference_run` getters.
|
|
278
|
+
|
|
279
|
+
Rust callers that construct `BenchmarkResult` with a struct literal must add
|
|
280
|
+
the new `pi_equivalent`, `reference_machine` and `reference_run` fields. This
|
|
281
|
+
source change follows from extending the public result struct; callers that
|
|
282
|
+
obtain results from benchmark functions keep their existing call signatures.
|
|
283
|
+
|
|
284
|
+
Every multiplier is a double-precision value. It is available for completed
|
|
285
|
+
results, including unstable ones. Failed/cancelled results have no multiplier:
|
|
286
|
+
`None` in Python/Rust, `nil` in Swift, or a zero presence flag in C.
|
|
287
|
+
|
|
288
|
+
`PI_REFERENCE_RUN` / Swift `piReferenceRun` describes the final six-run
|
|
289
|
+
calibration series, starting at its first warmup and ending with the final
|
|
290
|
+
measurement, before final cooling. It began on **2026-10-23 at
|
|
291
|
+
14:59:50.517391 UTC** (Unix seconds `1792767590.517391`); CPU temperature was
|
|
292
|
+
**41.35 °C** at the beginning and **66.65 °C** at the end. Preparation, plateau
|
|
293
|
+
profiling and the later cooling period are outside these boundaries. The
|
|
294
|
+
reference series ended on 23 October, including in Moscow; the larger session
|
|
295
|
+
with preparation and cooling crossed midnight.
|
|
296
|
+
|
|
297
|
+
Each benchmark had three independent measurements of 300 seconds, with cooling
|
|
298
|
+
verified by temperature readings between experiments. The stored score pools
|
|
299
|
+
all three measurements as **total iterations / total actual elapsed seconds**;
|
|
300
|
+
it is neither the best repeat nor a rounded display value:
|
|
301
|
+
|
|
302
|
+
| Benchmark | Iterations | Actual measurement seconds | Reference iterations/s |
|
|
303
|
+
|---|---:|---:|---:|
|
|
304
|
+
| `single_core` | 42,508,112 | 900.000162475 | 47231.227029007096 |
|
|
305
|
+
| `multi_core` | 163,757,952 | 900.000523364 | 181953.17419139884 |
|
|
306
|
+
|
|
307
|
+
The historical calibration used **1248 seconds (20 minutes 48 seconds) of
|
|
308
|
+
warmup before every measurement**. This is the conservative 960-second plateau
|
|
309
|
+
boundary plus 30%, based on both throughput and thermal establishment. There
|
|
310
|
+
was no substantial prolonged throughput decline during profiling. The
|
|
311
|
+
library's runtime defaults remain **120 seconds warmup / 60 seconds
|
|
312
|
+
measurement**; callers can choose their own windows. The reference warmup is
|
|
313
|
+
recorded provenance, not an automatic runtime setting.
|
|
314
|
+
|
|
315
|
+
The metadata types are `ReferenceMachine`, `ReferenceRun` and
|
|
316
|
+
`ReferenceBenchmarkResult` in Rust, Python and Swift. In Rust/Python their
|
|
317
|
+
fields are:
|
|
318
|
+
|
|
319
|
+
- `ReferenceMachine`: `name`, `short_name`, `os_name`, `os_version`,
|
|
320
|
+
`cpu_architecture`, `memory_bytes` and `cpu_cores`.
|
|
321
|
+
- `ReferenceRun`: `started_at_unix_seconds`, `start_temperature_c`,
|
|
322
|
+
`end_temperature_c`, `warmup_seconds` and `results`. Temperatures are in
|
|
323
|
+
Celsius; the warmup is in seconds before **each** reference measurement.
|
|
324
|
+
- `ReferenceBenchmarkResult`: `benchmark` and `score` (iterations/s).
|
|
325
|
+
`results` contains two pooled entries, one per benchmark, rather than six
|
|
326
|
+
separate repeats.
|
|
327
|
+
|
|
328
|
+
Swift uses camelCase fields, such as `shortName`, `startedAtUnixSeconds` and
|
|
329
|
+
`startTemperatureC`. Python additionally offers the timezone-aware UTC
|
|
330
|
+
`started_at` datetime; Swift offers `startedAt: Date` for the same instant.
|
|
331
|
+
The frozen Python records use a tuple for results; Swift returns immutable
|
|
332
|
+
value snapshots. Reading the Python globals does not load the native library.
|
|
333
|
+
|
|
334
|
+
[Calibration values and provenance](native/reference-calibration.json) include
|
|
335
|
+
the original kernel commit, binary SHA-256, raw pooled totals and series
|
|
336
|
+
boundaries. The calibration used the unchanged scalar kernel at commit
|
|
337
|
+
`1b6771c1fe47514edfe72384b76a1d595cb2ff10`. Ambient conditions were not
|
|
338
|
+
controlled; the measured idle temperature shifted, so later cooling also
|
|
339
|
+
accepted a documented stable idle plateau. Ratios describe these workloads
|
|
340
|
+
and this reference configuration. The library reads these fixed values
|
|
341
|
+
locally; it does not connect to the Pi, query sensors or require the original
|
|
342
|
+
experiment directory.
|
|
343
|
+
|
|
344
|
+
The only editable package version is `[project].version` in `pyproject.toml`.
|
|
345
|
+
The version values in `Cargo.toml`, the package's `Cargo.lock` entry and the
|
|
346
|
+
Rust/Swift dependency pins below are generated copies. `benchset.__version__`
|
|
347
|
+
and result objects read installed Python package metadata through
|
|
212
348
|
`importlib.metadata`; no Python source version constant needs updating.
|
|
213
|
-
|
|
214
|
-
|
|
349
|
+
Rust, C and Swift read the version compiled from the generated Cargo metadata.
|
|
350
|
+
Python builds (including metadata, sdist, wheel and editable hooks),
|
|
351
|
+
`scripts/build_native.py` and `scripts/package_native.py` automatically refresh
|
|
352
|
+
these copies before building. Consumers decide which versions and measurement
|
|
353
|
+
settings are comparable.
|
|
215
354
|
|
|
216
355
|
## Embed in Rust
|
|
217
356
|
|
|
218
357
|
```toml
|
|
219
358
|
[dependencies]
|
|
220
|
-
benchset = "0.0.
|
|
221
|
-
#
|
|
222
|
-
# benchset = {
|
|
359
|
+
benchset = "0.0.4"
|
|
360
|
+
# For changes from a local source checkout, use:
|
|
361
|
+
# benchset = { path = "../benchset" }
|
|
223
362
|
```
|
|
224
363
|
|
|
225
364
|
```rust
|
|
@@ -227,7 +366,12 @@ use benchset::{run, Benchmark, Cancellation, Options};
|
|
|
227
366
|
let cancellation = Cancellation::default();
|
|
228
367
|
let result = run(Benchmark::MultiCore, Options::default(), &cancellation,
|
|
229
368
|
|progress| println!("{:?}: {}", progress.phase, progress.fraction));
|
|
230
|
-
|
|
369
|
+
if let (Some(score), Some(equivalent)) = (result.score, result.pi_equivalent) {
|
|
370
|
+
println!("{score:.3} iterations/s, {equivalent:.3} x {}", result.reference_machine.short_name);
|
|
371
|
+
} else {
|
|
372
|
+
println!("{:?}: {}", result.status, result.reason);
|
|
373
|
+
}
|
|
374
|
+
println!("Reference warmup: {} s", result.reference_run.warmup_seconds);
|
|
231
375
|
```
|
|
232
376
|
|
|
233
377
|
The cancellation token can be cloned and cancelled from another thread. It is
|
|
@@ -248,25 +392,66 @@ dynamic loading. `include/benchset.h` documents structures, status codes and
|
|
|
248
392
|
lifetime rules. `examples/native/c.c` demonstrates configuration and progress.
|
|
249
393
|
|
|
250
394
|
```c
|
|
395
|
+
/* Inside main(); callback/context are supplied by the host application. */
|
|
396
|
+
if (benchset_abi_version() != BENCHSET_ABI_VERSION) return 1;
|
|
251
397
|
BenchsetConfig config;
|
|
252
|
-
benchset_default_config(&config);
|
|
398
|
+
if (!benchset_default_config(&config)) return 1;
|
|
253
399
|
config.benchmark = BENCHSET_MULTI_CORE;
|
|
254
400
|
BenchsetHandle *handle = benchset_create();
|
|
255
401
|
if (handle) {
|
|
256
402
|
benchset_run(handle, &config, callback, context);
|
|
257
|
-
|
|
258
|
-
if (
|
|
259
|
-
|
|
403
|
+
BenchsetResultV3 result;
|
|
404
|
+
if (benchset_result_v3(handle, &result, sizeof(result))) {
|
|
405
|
+
const BenchsetReferenceMachine *machine = result.reference_machine;
|
|
406
|
+
const BenchsetReferenceRun *reference = result.reference_run;
|
|
407
|
+
/* machine and reference are available even after failure/cancellation. */
|
|
408
|
+
printf("Reference: %s, warmup %.0f s\n", machine->name, reference->warmup_seconds);
|
|
409
|
+
if (result.base.base.status == BENCHSET_COMPLETED && result.base.has_pi_equivalent) {
|
|
410
|
+
/* result.base.base.score is iterations/s; result.base.pi_equivalent is a multiplier. */
|
|
411
|
+
}
|
|
412
|
+
/* The metadata pointers remain valid after benchset_free(handle). */
|
|
260
413
|
}
|
|
261
414
|
benchset_free(handle);
|
|
262
415
|
}
|
|
263
416
|
```
|
|
264
417
|
|
|
265
418
|
Call `benchset_cancel(handle)` from another thread or a progress callback.
|
|
266
|
-
Handles are single-use.
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
419
|
+
Handles are single-use. Result/sample getters are used after `benchset_run`
|
|
420
|
+
returns. The reason string is borrowed until the handle is freed; the version
|
|
421
|
+
string is valid for the loaded library's lifetime. Progress pointers are
|
|
422
|
+
borrowed only during the callback. Do not free a handle while it is in use or
|
|
423
|
+
throw/unwind through a C callback. Invalid configuration produces a failed result.
|
|
424
|
+
|
|
425
|
+
The C ABI version remains 1. The additive, size-checked
|
|
426
|
+
`benchset_reference_machine`, `benchset_reference_run` and indexed
|
|
427
|
+
`benchset_reference_result` getters need no handle. Their
|
|
428
|
+
immutable strings remain valid for the loaded library's lifetime. Pass the
|
|
429
|
+
exact output structure size to these getters, `benchset_result_v2` and
|
|
430
|
+
`benchset_result_v3`;
|
|
431
|
+
failure returns zero and leaves the output unchanged. Any nonzero
|
|
432
|
+
`has_pi_equivalent` flag means present, including a multiplier of `0.0`.
|
|
433
|
+
Existing ABI-1 configurations and the original 88-byte `BenchsetResult`
|
|
434
|
+
layout/getter retain their behavior, so existing consumers continue to run.
|
|
435
|
+
New consumers check `benchset_abi_version()` and use the extended result getter
|
|
436
|
+
to access the multiplier. V2 and V3 name additive result formats; they use the
|
|
437
|
+
same ABI-1 configuration. Older libraries can report ABI 1 while lacking the
|
|
438
|
+
new getters, so the Python wrapper checks its required symbols before allocating
|
|
439
|
+
a handle.
|
|
440
|
+
|
|
441
|
+
`BenchsetResultV3` adds a complete `BenchsetResultV2 base` followed by const
|
|
442
|
+
`reference_machine` and `reference_run` pointers. Both pointers are non-null
|
|
443
|
+
for every available result. They and their strings remain immutable and valid
|
|
444
|
+
after `benchset_free(handle)`, until the library is unloaded. Do not use the
|
|
445
|
+
freed handle or its reason string. The ABI version remains 1, and the V1
|
|
446
|
+
(88-byte) and V2 (104-byte) structures and getters retain their layouts and
|
|
447
|
+
behavior. V3 is 120 bytes on
|
|
448
|
+
the supported 64-bit platforms.
|
|
449
|
+
|
|
450
|
+
The C metadata types are `BenchsetReferenceMachine`, `BenchsetReferenceRun`
|
|
451
|
+
and `BenchsetReferenceBenchmarkResult`. `BenchsetReferenceRun.result_count`
|
|
452
|
+
replaces the Rust/Python/Swift `results` collection: retrieve each entry with
|
|
453
|
+
`benchset_reference_result(index, &entry, sizeof(entry))`, using zero-based
|
|
454
|
+
indices smaller than `result_count`.
|
|
270
455
|
|
|
271
456
|
When statically linking Rust into a foreign application, system libraries may
|
|
272
457
|
also be required. Obtain their list with
|
|
@@ -286,11 +471,13 @@ the same repository. Rust is not required by the consumer.
|
|
|
286
471
|
For a Swift manifest, add:
|
|
287
472
|
|
|
288
473
|
```swift
|
|
289
|
-
.package(url: "https://github.com/mutating/benchset.git", .exact("0.0.
|
|
474
|
+
.package(url: "https://github.com/mutating/benchset.git", .exact("0.0.4"))
|
|
290
475
|
```
|
|
291
476
|
|
|
292
477
|
Add `.product(name: "Benchset", package: "benchset")` to your target's
|
|
293
478
|
dependencies. Pinning a version also pins the benchmark implementation.
|
|
479
|
+
For unreleased changes, build the Apple package from source as shown below
|
|
480
|
+
and use `.package(path: "../benchset")` instead.
|
|
294
481
|
|
|
295
482
|
For offline use, download and extract **`Benchset-Swift.zip`** from the release
|
|
296
483
|
and add the extracted directory as a local package. It contains the wrapper,
|
|
@@ -304,6 +491,12 @@ let runner = BenchmarkRunner()
|
|
|
304
491
|
let result = try runner.run(.multiCore, warmupSeconds: 120, measurementSeconds: 60) {
|
|
305
492
|
progress in print(progress.fraction)
|
|
306
493
|
}
|
|
494
|
+
if let score = result.score, let equivalent = result.piEquivalent {
|
|
495
|
+
print("\(score) \(result.unit), \(equivalent) x \(result.referenceMachine.shortName)")
|
|
496
|
+
} else {
|
|
497
|
+
print(result.status, result.reason as Any)
|
|
498
|
+
}
|
|
499
|
+
print(result.referenceRun.startedAt, result.referenceRun.warmupSeconds)
|
|
307
500
|
// Another thread may call runner.cancel() while run is active.
|
|
308
501
|
```
|
|
309
502
|
|
|
@@ -348,6 +541,14 @@ installation. Release wheels are platform-specific but interpreter-independent
|
|
|
348
541
|
correctness, result accounting, progress, cancellation and API/CLI behavior;
|
|
349
542
|
they do not enforce speed thresholds in CI.
|
|
350
543
|
|
|
544
|
+
`python -m pytest tests/test_reference_artifacts.py` also builds and runs
|
|
545
|
+
consumers of unpacked crates, source distributions, wheels and native ZIPs
|
|
546
|
+
outside the checkout. Build the Apple package first to include its unpacked
|
|
547
|
+
Swift consumer and symbol checks for both XCFramework architectures. All smoke
|
|
548
|
+
measurements use short explicit windows, never the historical calibration
|
|
549
|
+
warmup. The [Pi equivalent test plan](tests/pi-equivalent-plan.md) records both
|
|
550
|
+
rounds of independent test reviews and their deduplicated scenarios.
|
|
551
|
+
|
|
351
552
|
## Test coverage
|
|
352
553
|
|
|
353
554
|
The [test matrix](tests/coverage-plan.md) combines five independent reviews and
|
|
@@ -380,10 +581,21 @@ All distributions are released from this repository by
|
|
|
380
581
|
`.github/workflows/release.yml`. A push to `main` checks the common package
|
|
381
582
|
version. An unreleased version is built and published automatically; a version
|
|
382
583
|
whose managed GitHub Release is already published is skipped. To release a new
|
|
383
|
-
version,
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
584
|
+
version, change only `[project].version` in `pyproject.toml`, commit it and push
|
|
585
|
+
to `main`. Use an `X.Y.Z` version. Builds automatically synchronize the Cargo
|
|
586
|
+
manifest, lockfile entry and README dependency pins; no separate version command
|
|
587
|
+
is needed. The prepared release commit freezes those generated values for all
|
|
588
|
+
published source archives and tags. `python scripts/version.py --check` remains
|
|
589
|
+
an optional diagnostic; it does not have to pass on an unbuilt checkout after a
|
|
590
|
+
version edit.
|
|
591
|
+
|
|
592
|
+
For a local native build after editing the version, use
|
|
593
|
+
`python scripts/build_native.py`; for native/Swift archives use
|
|
594
|
+
`python scripts/package_native.py --target <target>` (add `--apple` for the
|
|
595
|
+
universal Swift package). Cargo reads its package version before `build.rs`
|
|
596
|
+
runs, so direct `cargo build`/`cargo package` use the already-generated manifest.
|
|
597
|
+
Published crates contain that manifest and still build without Python. Do not
|
|
598
|
+
create or move release tags manually.
|
|
387
599
|
|
|
388
600
|
The workflow performs these steps:
|
|
389
601
|
|
|
@@ -394,8 +606,9 @@ The workflow performs these steps:
|
|
|
394
606
|
the Linux containers; update the pin and package version together when
|
|
395
607
|
changing the release toolchain.
|
|
396
608
|
3. Compute the XCFramework archive checksum and create a detached release
|
|
397
|
-
commit
|
|
398
|
-
commit
|
|
609
|
+
commit containing generated version values and `Package.swift`. Its parent
|
|
610
|
+
is the tested canonical source commit; unrelated source changes are rejected.
|
|
611
|
+
`main` keeps its local development manifest.
|
|
399
612
|
4. Build the sdist and crate from that exact release commit, then retain the
|
|
400
613
|
complete, checksummed release bundle as a GitHub Actions artifact.
|
|
401
614
|
5. Push `v<version>` at the prepared commit and populate a draft GitHub Release
|
|
@@ -9,8 +9,8 @@ let package = Package(
|
|
|
9
9
|
products: [.library(name: "Benchset", targets: ["Benchset"])],
|
|
10
10
|
targets: [
|
|
11
11
|
.binaryTarget(name: "CBenchset",
|
|
12
|
-
url: "https://github.com/mutating/benchset/releases/download/v0.0.
|
|
13
|
-
checksum: "
|
|
12
|
+
url: "https://github.com/mutating/benchset/releases/download/v0.0.4/Benchset.xcframework.zip",
|
|
13
|
+
checksum: "0e6643b1daa58773a93aec6b4228b2d81580f058dc5348609457363a9b5ec4ae"),
|
|
14
14
|
.target(name: "Benchset", dependencies: ["CBenchset"]),
|
|
15
15
|
.testTarget(name: "BenchsetTests", dependencies: ["Benchset"], path: "tests/swift")
|
|
16
16
|
]
|