evutils 0.3.10__tar.gz → 0.3.11__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.
- {evutils-0.3.10 → evutils-0.3.11}/.github/workflows/release.yaml +3 -3
- {evutils-0.3.10 → evutils-0.3.11}/PKG-INFO +11 -28
- {evutils-0.3.10 → evutils-0.3.11}/README.md +4 -22
- evutils-0.3.11/benchmarks/README.md +131 -0
- evutils-0.3.11/benchmarks/conftest.py +94 -0
- evutils-0.3.11/benchmarks/docker/Dockerfile.openeb +56 -0
- {evutils-0.3.10 → evutils-0.3.11}/benchmarks/readers.py +14 -3
- {evutils-0.3.10 → evutils-0.3.11}/benchmarks/test_compare.py +6 -3
- evutils-0.3.11/benchmarks/test_fixed_formats.py +119 -0
- {evutils-0.3.10 → evutils-0.3.11}/benchmarks/test_read.py +14 -10
- evutils-0.3.11/benchmarks/test_write.py +57 -0
- evutils-0.3.11/csrc/aer.c +36 -0
- evutils-0.3.11/csrc/dat.c +66 -0
- {evutils-0.3.10 → evutils-0.3.11}/csrc/evt3.c +4 -0
- evutils-0.3.11/csrc/include/evutils/aer.h +35 -0
- evutils-0.3.11/csrc/include/evutils/dat.h +40 -0
- {evutils-0.3.10 → evutils-0.3.11}/docs/source/conf.py +14 -5
- {evutils-0.3.10 → evutils-0.3.11}/pyproject.toml +37 -6
- evutils-0.3.11/scripts/generate_benchmark_table.py +117 -0
- evutils-0.3.11/scripts/generate_metadata.py +102 -0
- evutils-0.3.11/src/evutils/_jit.py +34 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/augment/_drop.py +3 -2
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/chunking.py +11 -12
- evutils-0.3.11/src/evutils/io/_aedat.py +86 -0
- evutils-0.3.11/src/evutils/io/_aer.py +245 -0
- evutils-0.3.11/src/evutils/io/_bin.py +86 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/io/_csv.py +66 -14
- evutils-0.3.11/src/evutils/io/_dat.py +320 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/io/_event_reader.py +203 -72
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/io/_event_writer.py +49 -26
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/io/_evt.py +217 -70
- evutils-0.3.11/src/evutils/io/_hdf5.py +295 -0
- evutils-0.3.11/src/evutils/io/_native_evt.py +981 -0
- evutils-0.3.11/src/evutils/io/_npz.py +192 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/io/_source.py +48 -2
- evutils-0.3.11/src/evutils/io/buffer.py +203 -0
- evutils-0.3.11/src/evutils/io/common.py +321 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/io/decoders.py +61 -37
- evutils-0.3.11/src/evutils/io/encoders.py +85 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/processing/_masking.py +8 -1
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/processing/_utils.py +3 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/random.py +4 -7
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/repr/_frame.py +32 -37
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/repr/_histogram.py +23 -22
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/repr/_timesurface.py +6 -6
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/repr/_tore.py +12 -11
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/repr/_voxel.py +6 -7
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/torch/__init__.py +1 -1
- evutils-0.3.11/src/evutils/types.py +298 -0
- evutils-0.3.11/src/evutils/utils/_checker.py +105 -0
- evutils-0.3.11/src/evutils/vis/__init__.py +9 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/open3d.py +12 -2
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/plot3d.py +32 -1
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/_base.py +23 -6
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/metavision.py +34 -15
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg.py +51 -5
- {evutils-0.3.10 → evutils-0.3.11}/tests/conftest.py +7 -22
- evutils-0.3.11/tests/conftest_utils.py +69 -0
- evutils-0.3.11/tests/io/test_aer.py +32 -0
- evutils-0.3.11/tests/io/test_dat.py +44 -0
- evutils-0.3.11/tests/io/test_evt.py +303 -0
- {evutils-0.3.10 → evutils-0.3.11}/uv.lock +598 -507
- evutils-0.3.10/benchmarks/README.md +0 -102
- evutils-0.3.10/benchmarks/conftest.py +0 -75
- evutils-0.3.10/benchmarks/docker/Dockerfile.openeb +0 -57
- evutils-0.3.10/benchmarks/test_write.py +0 -31
- evutils-0.3.10/src/evutils/io/_aedat.py +0 -33
- evutils-0.3.10/src/evutils/io/_aer.py +0 -32
- evutils-0.3.10/src/evutils/io/_bin.py +0 -31
- evutils-0.3.10/src/evutils/io/_dat.py +0 -30
- evutils-0.3.10/src/evutils/io/_hdf5.py +0 -187
- evutils-0.3.10/src/evutils/io/_native_evt.py +0 -481
- evutils-0.3.10/src/evutils/io/_npz.py +0 -30
- evutils-0.3.10/src/evutils/io/buffer.py +0 -98
- evutils-0.3.10/src/evutils/io/common.py +0 -207
- evutils-0.3.10/src/evutils/io/encoders.py +0 -68
- evutils-0.3.10/src/evutils/types.py +0 -127
- evutils-0.3.10/src/evutils/utils/_checker.py +0 -32
- evutils-0.3.10/src/evutils/vis/__init__.py +0 -5
- evutils-0.3.10/tests/io/test_dat.py +0 -0
- evutils-0.3.10/tests/io/test_evt.py +0 -203
- {evutils-0.3.10 → evutils-0.3.11}/.dockerignore +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/.github/workflows/test.yaml +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/.gitignore +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/.gitmodules +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/CMakeLists.txt +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/LICENSE +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/csrc/evt2.c +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/csrc/evt21.c +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/csrc/evutils.c +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/csrc/include/evutils/compat.h +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/csrc/include/evutils/evt2.h +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/csrc/include/evutils/evt21.h +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/csrc/include/evutils/evt3.h +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/csrc/include/evutils/evutils.h +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/csrc/include/evutils/parser.h +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/csrc/include/evutils/types.h +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/docker/Dockerfile +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/docs/Makefile +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/docs/make.bat +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/docs/source/_static/event_hexagon_broken.webp +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/docs/source/_templates/autoapi/python/module.rst +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/docs/source/benchmarks/README.md +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/docs/source/index.rst +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/__init__.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/augment/__init__.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/dataset/__init__.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/io/__init__.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/processing/__init__.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/repr/__init__.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/utils/__init__.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/__init__.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/.git +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/.gitignore +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/LICENSE +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/README.md +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/__init__.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/base/__init__.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/base/base_model.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/data/.gitignore +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/image_reconstructor.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/model/__init__.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/model/model.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/model/submodules.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/model/unet.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/options/__init__.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/options/inference_options.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/pretrained/.gitignore +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/run_reconstruction.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/scripts/embed_reconstructed_images_in_rosbag.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/scripts/extract_events_from_rosbag.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/scripts/image_folder_to_rosbag.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/scripts/resample_reconstructions.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/utils/__init__.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/utils/event_readers.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/utils/inference_utils.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/utils/loading_utils.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/utils/path_utils.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/utils/timers.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/src/evutils/vis/reconstructor/rpg_e2vid/utils/util.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/tests/io/conftest.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/tests/io/test_bin.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/tests/io/test_csv.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/tests/io/test_hdf5.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/tests/io/test_npz.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/tests/test_random.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/tests/test_types.py +0 -0
- {evutils-0.3.10 → evutils-0.3.11}/tests/test_vis.py +0 -0
|
@@ -51,7 +51,7 @@ jobs:
|
|
|
51
51
|
CIBW_ARCHS_MACOS: "x86_64 arm64"
|
|
52
52
|
|
|
53
53
|
- name: Upload wheels
|
|
54
|
-
uses: actions/upload-artifact@
|
|
54
|
+
uses: actions/upload-artifact@v7
|
|
55
55
|
with:
|
|
56
56
|
name: dist-${{ matrix.os }}
|
|
57
57
|
path: wheelhouse/*.whl
|
|
@@ -75,7 +75,7 @@ jobs:
|
|
|
75
75
|
run: pipx run build --sdist
|
|
76
76
|
|
|
77
77
|
- name: Upload sdist
|
|
78
|
-
uses: actions/upload-artifact@
|
|
78
|
+
uses: actions/upload-artifact@v7
|
|
79
79
|
with:
|
|
80
80
|
name: dist-sdist
|
|
81
81
|
path: dist/*.tar.gz
|
|
@@ -140,4 +140,4 @@ jobs:
|
|
|
140
140
|
|
|
141
141
|
- name: Deploy to GitHub Pages
|
|
142
142
|
id: deployment
|
|
143
|
-
uses: actions/deploy-pages@
|
|
143
|
+
uses: actions/deploy-pages@v5
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: evutils
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.11
|
|
4
4
|
Summary: Utilities for event-based vision
|
|
5
5
|
Keywords: events,dvs,neuromorphic,vision,event-based
|
|
6
6
|
Author-Email: Jakub Mandula <jakub.mandula@pbl.ee.ethz.ch>
|
|
@@ -30,17 +30,17 @@ Project-URL: Homepage, https://mandulaj.github.io/evutils/
|
|
|
30
30
|
Requires-Python: >=3.10
|
|
31
31
|
Requires-Dist: numpy>=2.0.0
|
|
32
32
|
Requires-Dist: opencv-python>=4.2
|
|
33
|
+
Requires-Dist: numba>=0.57
|
|
33
34
|
Provides-Extra: pandas
|
|
34
35
|
Requires-Dist: pandas>=2.3.3; extra == "pandas"
|
|
35
|
-
Provides-Extra: numba
|
|
36
|
-
Requires-Dist: numba>=0.57; extra == "numba"
|
|
37
36
|
Provides-Extra: torch
|
|
38
37
|
Requires-Dist: torch>=2.0; extra == "torch"
|
|
39
38
|
Provides-Extra: hdf5
|
|
40
39
|
Requires-Dist: hdf5plugin==6.0.0; extra == "hdf5"
|
|
41
|
-
Requires-Dist: h5py
|
|
40
|
+
Requires-Dist: h5py>=3.16.0; extra == "hdf5"
|
|
42
41
|
Provides-Extra: vis
|
|
43
42
|
Requires-Dist: matplotlib>=3.1; extra == "vis"
|
|
43
|
+
Requires-Dist: open3d>=0.19.0; python_version < "3.13" and extra == "vis"
|
|
44
44
|
Requires-Dist: scipy>=1.15.3; extra == "vis"
|
|
45
45
|
Requires-Dist: tqdm>=4.41; extra == "vis"
|
|
46
46
|
Provides-Extra: test
|
|
@@ -48,7 +48,8 @@ Requires-Dist: pytest>=9.0.2; extra == "test"
|
|
|
48
48
|
Requires-Dist: pytest-benchmark>=5.2.3; extra == "test"
|
|
49
49
|
Provides-Extra: compare
|
|
50
50
|
Requires-Dist: expelliarmus>=1.1.0; extra == "compare"
|
|
51
|
-
Requires-Dist: evlib; extra == "compare"
|
|
51
|
+
Requires-Dist: evlib>=0.12.0; python_version >= "3.11" and extra == "compare"
|
|
52
|
+
Requires-Dist: evlib>=0.8.0; python_version < "3.11" and extra == "compare"
|
|
52
53
|
Provides-Extra: docs
|
|
53
54
|
Requires-Dist: sphinx>=8.0.0; extra == "docs"
|
|
54
55
|
Requires-Dist: sphinx-autoapi>=3.6.1; extra == "docs"
|
|
@@ -58,7 +59,7 @@ Requires-Dist: sphinx_book_theme>=1.0.0; extra == "docs"
|
|
|
58
59
|
Requires-Dist: pydata_sphinx_theme>=0.19.0; extra == "docs"
|
|
59
60
|
Requires-Dist: myst-parser>=4.0.0; extra == "docs"
|
|
60
61
|
Provides-Extra: all
|
|
61
|
-
Requires-Dist: evutils[hdf5,
|
|
62
|
+
Requires-Dist: evutils[hdf5,pandas,torch,vis]; extra == "all"
|
|
62
63
|
Provides-Extra: dev
|
|
63
64
|
Requires-Dist: evutils[all,docs,test]; extra == "dev"
|
|
64
65
|
Description-Content-Type: text/markdown
|
|
@@ -83,10 +84,12 @@ This project draws inspiration from several excellent libraries in the event-bas
|
|
|
83
84
|
|
|
84
85
|
|
|
85
86
|
## Installation
|
|
86
|
-
We recommend installing `evutils` using `uv`.
|
|
87
|
+
We recommend installing `evutils` using `uv`.
|
|
87
88
|
### From PyPi
|
|
88
89
|
```bash
|
|
89
|
-
uv add evutils
|
|
90
|
+
uv add evutils # Basic library
|
|
91
|
+
uv add evutils[all] # All groups (pandas, numba, torch, hdf5, etc..)
|
|
92
|
+
uv add evutils[dev] # Dev group
|
|
90
93
|
```
|
|
91
94
|
|
|
92
95
|
### From Git
|
|
@@ -187,26 +190,6 @@ uv run pytest benchmarks/ --benchmark-group-by=param:fmt # compare libraries
|
|
|
187
190
|
|
|
188
191
|
The benchmarks download a real Prophesee recording on first use. Optional cross-library comparisons run automatically once the libraries are installed (`uv pip install -e ".[compare]"`); OpenEB/Metavision is compared via the Docker image in `benchmarks/docker/`. See [`benchmarks/README.md`](benchmarks/README.md) for details.
|
|
189
192
|
|
|
190
|
-
Decode/encode throughput on a 12th Gen Intel Core i7-1280P (millions of events per second, higher is better):
|
|
191
|
-
|
|
192
|
-
**Read** (full-file decode)
|
|
193
|
-
|
|
194
|
-
| Format | evutils | expelliarmus | evlib |
|
|
195
|
-
| ------ | ------: | -----------: | ----: |
|
|
196
|
-
| EVT2 | 91 | 105 | 5 |
|
|
197
|
-
| EVT2.1 | 72 | – | – |
|
|
198
|
-
| EVT3 | 53 | 41 | 5 |
|
|
199
|
-
|
|
200
|
-
**Write** (evutils; expelliarmus/evlib are read-only for these formats)
|
|
201
|
-
|
|
202
|
-
| Format | evutils |
|
|
203
|
-
| ------ | ------: |
|
|
204
|
-
| EVT2 | 146 |
|
|
205
|
-
| EVT2.1 | 110 |
|
|
206
|
-
| EVT3 | 74 |
|
|
207
|
-
|
|
208
|
-
(`–` = format not supported by that library.)
|
|
209
|
-
|
|
210
193
|
|
|
211
194
|
## Acknowledgements
|
|
212
195
|
|
|
@@ -18,10 +18,12 @@ This project draws inspiration from several excellent libraries in the event-bas
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
## Installation
|
|
21
|
-
We recommend installing `evutils` using `uv`.
|
|
21
|
+
We recommend installing `evutils` using `uv`.
|
|
22
22
|
### From PyPi
|
|
23
23
|
```bash
|
|
24
|
-
uv add evutils
|
|
24
|
+
uv add evutils # Basic library
|
|
25
|
+
uv add evutils[all] # All groups (pandas, numba, torch, hdf5, etc..)
|
|
26
|
+
uv add evutils[dev] # Dev group
|
|
25
27
|
```
|
|
26
28
|
|
|
27
29
|
### From Git
|
|
@@ -122,26 +124,6 @@ uv run pytest benchmarks/ --benchmark-group-by=param:fmt # compare libraries
|
|
|
122
124
|
|
|
123
125
|
The benchmarks download a real Prophesee recording on first use. Optional cross-library comparisons run automatically once the libraries are installed (`uv pip install -e ".[compare]"`); OpenEB/Metavision is compared via the Docker image in `benchmarks/docker/`. See [`benchmarks/README.md`](benchmarks/README.md) for details.
|
|
124
126
|
|
|
125
|
-
Decode/encode throughput on a 12th Gen Intel Core i7-1280P (millions of events per second, higher is better):
|
|
126
|
-
|
|
127
|
-
**Read** (full-file decode)
|
|
128
|
-
|
|
129
|
-
| Format | evutils | expelliarmus | evlib |
|
|
130
|
-
| ------ | ------: | -----------: | ----: |
|
|
131
|
-
| EVT2 | 91 | 105 | 5 |
|
|
132
|
-
| EVT2.1 | 72 | – | – |
|
|
133
|
-
| EVT3 | 53 | 41 | 5 |
|
|
134
|
-
|
|
135
|
-
**Write** (evutils; expelliarmus/evlib are read-only for these formats)
|
|
136
|
-
|
|
137
|
-
| Format | evutils |
|
|
138
|
-
| ------ | ------: |
|
|
139
|
-
| EVT2 | 146 |
|
|
140
|
-
| EVT2.1 | 110 |
|
|
141
|
-
| EVT3 | 74 |
|
|
142
|
-
|
|
143
|
-
(`–` = format not supported by that library.)
|
|
144
|
-
|
|
145
127
|
|
|
146
128
|
## Acknowledgements
|
|
147
129
|
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Benchmarks
|
|
2
|
+
|
|
3
|
+
Read/write throughput benchmarks for the native EVT2 / EVT2.1 / EVT3 codecs, plus optional comparisons against other event libraries.
|
|
4
|
+
|
|
5
|
+
These benchmarks are **not** part of the normal test run (which uses `testpaths = ["tests"]`). They must be executed explicitly from the repository root.
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
Run the default suite (evutils only, plus any installed comparison libraries):
|
|
10
|
+
```bash
|
|
11
|
+
pytest benchmarks/
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Run specific benchmarks:
|
|
15
|
+
```bash
|
|
16
|
+
pytest benchmarks/test_read.py # just reads
|
|
17
|
+
pytest benchmarks/test_write.py # just writes
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Benchmark Options
|
|
21
|
+
|
|
22
|
+
### Datasets
|
|
23
|
+
You can benchmark against two datasets using the `--dataset` flag. The necessary files are automatically downloaded and cached on first use.
|
|
24
|
+
- `--dataset small` (default): A ~1GB memory footprint dataset (hand recordings).
|
|
25
|
+
- `--dataset large`: A massive multi-GB dataset designed to test the streaming and chunking capabilities of the decoders.
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pytest benchmarks/ --dataset large
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Filtering Readers
|
|
32
|
+
The benchmark tests are fully parametrized by the reader name. You can effortlessly exclude specific third-party libraries using pytest's standard `-k` flag (for example, if they are slow or misbehaving on large datasets):
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pytest benchmarks/ -k "not evlib" --dataset large
|
|
36
|
+
pytest benchmarks/ -k "not evlib and not openeb"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## File Structure
|
|
40
|
+
|
|
41
|
+
| File | What it benchmarks |
|
|
42
|
+
|------|--------------------|
|
|
43
|
+
| `test_read.py` | `evutils` decode throughput (evt2/evt21/evt3), asserts count vs reference |
|
|
44
|
+
| `test_write.py` | `evutils` encode throughput (payload = first 5M events of the real evt3 file) |
|
|
45
|
+
| `test_fixed_formats.py` | `evutils` read/write for DAT and AER (+ expelliarmus on DAT read) |
|
|
46
|
+
| `test_compare.py` | third-party readers from `readers.py` (auto-skip if not installed) |
|
|
47
|
+
| `readers.py` | adapter registry — one entry per external library |
|
|
48
|
+
|
|
49
|
+
*Note: DAT reuses the shared EVT3 reference events (its 14-bit coords fit 1280×720). AER is 9-bit and timestamp-less (GenX320-class), so it uses a separate small synthetic fixture.*
|
|
50
|
+
|
|
51
|
+
## Comparing Against Other Libraries
|
|
52
|
+
|
|
53
|
+
Install the optional readers and run with grouping so every library lines up per format:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pip install evutils[compare] # expelliarmus, evlib
|
|
57
|
+
pytest benchmarks/ --benchmark-group-by=param:fmt --benchmark-columns=mean,ops
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Each library reads inside a lazy import. If a library is uninstalled or broken, its benchmarks simply **skip**. To add another library, append a `Reader(...)` entry to `readers.py`.
|
|
61
|
+
|
|
62
|
+
## Benchmark Comparison (Mean Time in Seconds)
|
|
63
|
+
|
|
64
|
+
### Reading
|
|
65
|
+
|
|
66
|
+
| Library | EVT2 | EVT21 | EVT3 |
|
|
67
|
+
|---|---|---|---|
|
|
68
|
+
| **evutils** | 0.138 s | 0.070 s | 0.292 s |
|
|
69
|
+
| **evlib** | 4.410 s | N/A | 4.327 s |
|
|
70
|
+
| **expelliarmus** | 0.128 s | N/A | 0.341 s |
|
|
71
|
+
|
|
72
|
+
### Writing
|
|
73
|
+
|
|
74
|
+
| Library | EVT2 | EVT21 | EVT3 |
|
|
75
|
+
|---|---|---|---|
|
|
76
|
+
| **evutils** | 0.013 s | 0.028 s | 0.041 s |
|
|
77
|
+
| **expelliarmus** | 0.077 s | N/A | 0.097 s |
|
|
78
|
+
|
|
79
|
+
**Hardware:** 12th Gen Intel(R) Core(TM) i7-1280P | **OS:** Linux 7.1.1-3-MANJARO | **Python:** 3.12.13
|
|
80
|
+
|
|
81
|
+
*Lower is better. Generated dynamically by `scripts/generate_benchmark_table.py`.*
|
|
82
|
+
|
|
83
|
+
> **Note**: `tonic` is intentionally not included. It has no standalone EVT reader and reads Prophesee data through `expelliarmus` internally, so benchmarking it would just re-measure `expelliarmus`.
|
|
84
|
+
|
|
85
|
+
## OpenEB / Metavision (via Docker)
|
|
86
|
+
|
|
87
|
+
OpenEB isn't on PyPI and is painful to build locally, so there's an image that builds it once. Both commands must be run **from the repo root** (the build context must be the whole project so `evutils` is copied in):
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# Build the image (compiles OpenEB from source + installs evutils; slow, one-time)
|
|
91
|
+
docker build -t evutils-openeb -f benchmarks/docker/Dockerfile.openeb .
|
|
92
|
+
|
|
93
|
+
# Run the full suite (evutils + OpenEB), grouped per format
|
|
94
|
+
docker run --rm evutils-openeb
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The container's default command is `pytest benchmarks/ --benchmark-group-by=param:fmt`, so you get `evutils` and OpenEB side by side per format.
|
|
98
|
+
|
|
99
|
+
### Useful Variations
|
|
100
|
+
|
|
101
|
+
Persist the downloaded recording across runs (otherwise `--rm` discards the pytest cache and it re-downloads every time):
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
docker run --rm -v evutils-cache:/work/.pytest_cache evutils-openeb
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Run only the OpenEB comparison (skip the `evutils` rows):
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
docker run --rm evutils-openeb \
|
|
111
|
+
pytest benchmarks/test_compare.py --benchmark-group-by=param:fmt -q
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Drop into a shell to debug the build/run:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
docker run --rm -it evutils-openeb bash
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Build a different OpenEB release if the default fails to build:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
docker build -t evutils-openeb --build-arg OPENEB_VERSION=5.0.0 \
|
|
124
|
+
-f benchmarks/docker/Dockerfile.openeb .
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Caveats
|
|
128
|
+
|
|
129
|
+
- The image targets **OpenEB 5.x on Ubuntu 22.04**; OpenEB's apt dependencies and install layout drift between releases, so the `apt-get`/`PYTHONPATH` lines may need tweaking. The Dockerfile imports `metavision_core` at build time, so a broken OpenEB install fails during `docker build` rather than silently skipping at run time.
|
|
130
|
+
- The first pass is slow: it compiles OpenEB (`-j$(nproc)`) and downloads the reference recording on first run.
|
|
131
|
+
- A repo-root `.dockerignore` keeps the build context small (excludes `.venv`, `build/`, `.git`, `data/`, `*.raw`, etc.).
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""Benchmark fixtures.
|
|
2
|
+
|
|
3
|
+
``EventFile`` and ``real_event_files`` are duplicated from ``tests/conftest.py``
|
|
4
|
+
on purpose: pytest only shares conftest fixtures downward, and ``benchmarks/``
|
|
5
|
+
is a sibling of ``tests/``, so there is no clean way to reuse them without a
|
|
6
|
+
repo-root conftest. Keep the two copies in sync.
|
|
7
|
+
"""
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
import pytest
|
|
13
|
+
|
|
14
|
+
from evutils.io import EventReader
|
|
15
|
+
|
|
16
|
+
sys.path.append(str(Path(__file__).parent.parent / "tests"))
|
|
17
|
+
from conftest_utils import EventFile, download_and_extract_gdrive, load_event_files
|
|
18
|
+
|
|
19
|
+
#: Cap on how many events are held in memory for the write benchmarks. Large
|
|
20
|
+
#: enough for a stable throughput measurement, small enough to stay light.
|
|
21
|
+
N_REFERENCE = 5_000_000
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@pytest.fixture(scope='session')
|
|
25
|
+
def real_event_files(request, benchmark_dataset):
|
|
26
|
+
"""Real Prophesee recordings (downloaded + cached on first use).
|
|
27
|
+
|
|
28
|
+
Returns ``{format: [EventFile(path, count)]}``.
|
|
29
|
+
"""
|
|
30
|
+
if benchmark_dataset == "large":
|
|
31
|
+
temp_dir = request.config.cache.mkdir("event_files_huge")
|
|
32
|
+
file_id = "1QPuilR1VD0rKyhVOlu1Y-HtkO4ZBc2Cz"
|
|
33
|
+
|
|
34
|
+
json_files = list(temp_dir.glob("*.json"))
|
|
35
|
+
if not json_files:
|
|
36
|
+
download_and_extract_gdrive(file_id, temp_dir, "huge.tar.zst")
|
|
37
|
+
|
|
38
|
+
return load_event_files(temp_dir)
|
|
39
|
+
else:
|
|
40
|
+
temp_dir = request.config.cache.mkdir("event_files")
|
|
41
|
+
file_id = "1uhOsWbp2o3CktsHrFkzGCNFbx0bQLsct"
|
|
42
|
+
filenames = {
|
|
43
|
+
'evt3': "hand_evt3.raw",
|
|
44
|
+
'evt21': "hand_evt21.raw",
|
|
45
|
+
'evt2': "hand_evt2.raw",
|
|
46
|
+
}
|
|
47
|
+
paths = {fmt: temp_dir / name for fmt, name in filenames.items()}
|
|
48
|
+
|
|
49
|
+
for key, path in paths.items():
|
|
50
|
+
if not path.exists():
|
|
51
|
+
download_and_extract_gdrive(file_id, temp_dir, "hand.tar.zst")
|
|
52
|
+
break
|
|
53
|
+
|
|
54
|
+
return load_event_files(temp_dir, paths)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@pytest.fixture(scope='session')
|
|
58
|
+
def reference_events(real_event_files):
|
|
59
|
+
"""First ``N_REFERENCE`` events of the real EVT3 recording as an AoS array.
|
|
60
|
+
|
|
61
|
+
Decoded once and reused as the payload for every write benchmark, so the
|
|
62
|
+
write benchmarks measure encoding cost only (not decoding).
|
|
63
|
+
"""
|
|
64
|
+
parts = []
|
|
65
|
+
total = 0
|
|
66
|
+
if 'evt3' not in real_event_files or not real_event_files['evt3']:
|
|
67
|
+
pytest.skip("No evt3 files available for reference events")
|
|
68
|
+
# Use the hand_evt3.raw file for reference events
|
|
69
|
+
ef = next((f for f in real_event_files['evt3'] if 'hand' in f.path.name), real_event_files['evt3'][0])
|
|
70
|
+
with EventReader(ef.path, n_events=1_000_000) as reader:
|
|
71
|
+
for chunk in reader:
|
|
72
|
+
parts.append(chunk.to_aos())
|
|
73
|
+
total += len(chunk)
|
|
74
|
+
if total >= N_REFERENCE:
|
|
75
|
+
break
|
|
76
|
+
return np.concatenate(parts)[:N_REFERENCE]
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def pytest_addoption(parser):
|
|
80
|
+
parser.addoption(
|
|
81
|
+
"--rounds", action="store", default=4, type=int, help="Number of benchmark rounds"
|
|
82
|
+
)
|
|
83
|
+
parser.addoption(
|
|
84
|
+
"--dataset", action="store", default="small", choices=["small", "large"],
|
|
85
|
+
help="Dataset size to use for benchmarks ('small' or 'large')"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
@pytest.fixture(scope="session")
|
|
89
|
+
def benchmark_rounds(request):
|
|
90
|
+
return request.config.getoption("--rounds")
|
|
91
|
+
|
|
92
|
+
@pytest.fixture(scope="session")
|
|
93
|
+
def benchmark_dataset(request):
|
|
94
|
+
return request.config.getoption("--dataset")
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# OpenEB (Metavision SDK, open-source edition) + evutils, for running the
|
|
2
|
+
# comparison benchmarks against OpenEB's RawReader.
|
|
3
|
+
#
|
|
4
|
+
# OpenEB is not on PyPI and is fiddly to build; this image does it once.
|
|
5
|
+
#
|
|
6
|
+
# Build (from the repo root, so the whole project is the build context):
|
|
7
|
+
# docker build -t evutils-openeb -f benchmarks/docker/Dockerfile.openeb .
|
|
8
|
+
#
|
|
9
|
+
# Run the benchmarks (downloads the reference recordings on first run):
|
|
10
|
+
# docker run --rm evutils-openeb
|
|
11
|
+
#
|
|
12
|
+
# Tip: add a repo-root .dockerignore (.venv, build/, .git, *.raw, data/) to keep
|
|
13
|
+
# the build context small.
|
|
14
|
+
#
|
|
15
|
+
# NOTE: OpenEB's exact apt dependencies and layout shift between releases. This
|
|
16
|
+
# targets OpenEB 5.x on Ubuntu 22.04 -- bump OPENEB_VERSION / tweak deps if the
|
|
17
|
+
# build fails.
|
|
18
|
+
FROM registry.git.ee.ethz.ch/pbl/research/event-camera/docker/open-eb-docker/openeb_base:latest
|
|
19
|
+
|
|
20
|
+
ARG USERNAME=user
|
|
21
|
+
ARG PASSWORD=password
|
|
22
|
+
ARG USER_ID=1000
|
|
23
|
+
ARG GROUP_ID=1000
|
|
24
|
+
|
|
25
|
+
# Validate that all required arguments are set
|
|
26
|
+
RUN : \
|
|
27
|
+
&& if [ -z "$USERNAME" ]; then echo "ERROR: USERNAME is not set."; exit 1; fi \
|
|
28
|
+
&& if [ -z "$PASSWORD" ]; then echo "ERROR: PASSWORD is not set."; exit 1; fi \
|
|
29
|
+
&& if [ -z "$USER_ID" ]; then echo "ERROR: USER_ID is not set."; exit 1; fi \
|
|
30
|
+
&& if [ -z "$GROUP_ID" ]; then echo "ERROR: GROUP_ID is not set."; exit 1; fi
|
|
31
|
+
|
|
32
|
+
RUN groupadd -g ${GROUP_ID} ${USERNAME} && useradd -u ${USER_ID} -g ${GROUP_ID} -ms /bin/bash ${USERNAME} && usermod -aG sudo ${USERNAME} && echo "${USERNAME}:${PASSWORD}" | chpasswd
|
|
33
|
+
|
|
34
|
+
USER ${USERNAME}
|
|
35
|
+
RUN echo "source /openeb/build/utils/scripts/setup_env.sh" >> /home/${USERNAME}/.bashrc
|
|
36
|
+
|
|
37
|
+
WORKDIR /home/${USERNAME}/work
|
|
38
|
+
COPY . /home/${USERNAME}/work
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# 2. Omit --python 3.12 so it defaults to the system Python (3.10) to match OpenEB
|
|
43
|
+
RUN uv venv --system-site-packages
|
|
44
|
+
RUN uv pip install --no-cache-dir -e ".[test,compare]"
|
|
45
|
+
|
|
46
|
+
ENV PATH="/home/${USERNAME}/work/.venv/bin:$PATH"
|
|
47
|
+
|
|
48
|
+
# 3. Source the OpenEB setup script directly during the RUN step
|
|
49
|
+
RUN . /openeb/build/utils/scripts/setup_env.sh && \
|
|
50
|
+
python3 -c "from metavision_core.event_io import RawReader; print('OpenEB OK')"
|
|
51
|
+
|
|
52
|
+
# 4. Use an ENTRYPOINT script to ensure OpenEB vars are loaded for ANY command you run
|
|
53
|
+
ENTRYPOINT ["/bin/bash", "-c", "source /openeb/build/utils/scripts/setup_env.sh && exec \"$@\"", "--"]
|
|
54
|
+
|
|
55
|
+
CMD ["pytest", "benchmarks/", "--benchmark-group-by=param:fmt", \
|
|
56
|
+
"--benchmark-columns=mean,ops", "-q"]
|
|
@@ -42,7 +42,12 @@ def _count(obj) -> int:
|
|
|
42
42
|
def _read_expelliarmus(path: str, fmt: str) -> int:
|
|
43
43
|
# https://github.com/open-neuromorphic/expelliarmus (evt2, evt3, dat)
|
|
44
44
|
from expelliarmus import Wizard
|
|
45
|
-
|
|
45
|
+
wiz = Wizard(encoding=fmt)
|
|
46
|
+
wiz.set_file(str(path))
|
|
47
|
+
total = 0
|
|
48
|
+
for chunk in wiz.read_chunk():
|
|
49
|
+
total += len(chunk)
|
|
50
|
+
return total
|
|
46
51
|
|
|
47
52
|
|
|
48
53
|
# NOTE: tonic (https://github.com/neuromorphs/tonic) has no standalone EVT/.raw
|
|
@@ -53,11 +58,17 @@ def _read_expelliarmus(path: str, fmt: str) -> int:
|
|
|
53
58
|
|
|
54
59
|
def _read_evlib(path: str, fmt: str) -> int:
|
|
55
60
|
# https://github.com/tallamjr/evlib (Rust-backed). Auto-detects the format;
|
|
56
|
-
# load_events() returns a polars LazyFrame
|
|
61
|
+
# load_events() returns a polars LazyFrame. To avoid OOM on huge files,
|
|
62
|
+
# we use an aggregation (pl.len()) and stream it using Polars streaming engine.
|
|
57
63
|
import evlib
|
|
64
|
+
import polars as pl
|
|
58
65
|
df = evlib.load_events(str(path))
|
|
59
66
|
if hasattr(df, "collect"):
|
|
60
|
-
|
|
67
|
+
try:
|
|
68
|
+
return df.select(pl.len()).collect(engine='streaming').item()
|
|
69
|
+
except TypeError:
|
|
70
|
+
# Fallback for older Polars versions
|
|
71
|
+
return df.select(pl.len()).collect(streaming=True).item()
|
|
61
72
|
return _count(df)
|
|
62
73
|
|
|
63
74
|
|
|
@@ -21,16 +21,19 @@ from readers import ALL_FORMATS, READERS
|
|
|
21
21
|
|
|
22
22
|
@pytest.mark.parametrize("fmt", ALL_FORMATS)
|
|
23
23
|
@pytest.mark.parametrize("reader", READERS, ids=lambda r: r.name)
|
|
24
|
-
def test_read_compare(benchmark, real_event_files, reader, fmt):
|
|
24
|
+
def test_read_compare(benchmark, benchmark_rounds, real_event_files, reader, fmt):
|
|
25
25
|
if fmt not in reader.formats:
|
|
26
26
|
pytest.skip(f"{reader.name} does not support {fmt}")
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
benchmark.group = f"read-{fmt}"
|
|
29
|
+
if fmt not in real_event_files or not real_event_files[fmt]:
|
|
30
|
+
pytest.skip(f"No files for format {fmt}")
|
|
31
|
+
ef = next((f for f in real_event_files[fmt] if 'hand' in f.path.name), real_event_files[fmt][0])
|
|
29
32
|
|
|
30
33
|
try:
|
|
31
34
|
n = benchmark.pedantic(
|
|
32
35
|
lambda: reader.read(ef.path, fmt),
|
|
33
|
-
rounds=
|
|
36
|
+
rounds=benchmark_rounds, iterations=1, warmup_rounds=1,
|
|
34
37
|
)
|
|
35
38
|
except ImportError as exc:
|
|
36
39
|
pytest.skip(f"{reader.name} not available: {exc}")
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"""Read/write throughput benchmarks for the fixed-record formats: DAT and AER.
|
|
2
|
+
|
|
3
|
+
DAT reuses the shared ``reference_events`` (1280x720 fits its 14-bit coords).
|
|
4
|
+
AER only has 9-bit coordinates and no timestamps, so it uses a separate small
|
|
5
|
+
(GenX320-sized) synthetic fixture.
|
|
6
|
+
|
|
7
|
+
pytest benchmarks/test_fixed_formats.py
|
|
8
|
+
|
|
9
|
+
The read benchmarks decode a file generated once per session; the write
|
|
10
|
+
benchmarks measure encoding of the in-memory events. expelliarmus (if installed)
|
|
11
|
+
is compared on the DAT read.
|
|
12
|
+
"""
|
|
13
|
+
import numpy as np
|
|
14
|
+
import pytest
|
|
15
|
+
|
|
16
|
+
from evutils.io import EventReader, EventWriter
|
|
17
|
+
from evutils.types import Event_dtype
|
|
18
|
+
|
|
19
|
+
AER_N = 5_000_000
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@pytest.fixture(scope="session")
|
|
23
|
+
def aer_events():
|
|
24
|
+
"""Small-resolution (GenX320) events for AER, which is 9-bit / timestamp-less."""
|
|
25
|
+
rng = np.random.default_rng(0)
|
|
26
|
+
ev = np.zeros(AER_N, dtype=Event_dtype)
|
|
27
|
+
ev["x"] = rng.integers(0, 320, AER_N)
|
|
28
|
+
ev["y"] = rng.integers(0, 320, AER_N)
|
|
29
|
+
ev["p"] = rng.integers(0, 2, AER_N)
|
|
30
|
+
return ev
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@pytest.fixture(scope="session")
|
|
34
|
+
def dat_file(reference_events, tmp_path_factory):
|
|
35
|
+
path = tmp_path_factory.mktemp("dat") / "ref.dat"
|
|
36
|
+
with EventWriter(path) as writer:
|
|
37
|
+
writer.write(reference_events)
|
|
38
|
+
return path
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@pytest.fixture(scope="session")
|
|
42
|
+
def aer_file(aer_events, tmp_path_factory):
|
|
43
|
+
path = tmp_path_factory.mktemp("aer") / "ref.aer"
|
|
44
|
+
with EventWriter(path) as writer:
|
|
45
|
+
writer.write(aer_events)
|
|
46
|
+
return path
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _read_all(path):
|
|
50
|
+
return len(EventReader(path).read_all())
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _write(path, events):
|
|
54
|
+
with EventWriter(path) as writer:
|
|
55
|
+
writer.write(events)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# --------------------------------------------------------------------------- #
|
|
59
|
+
# DAT
|
|
60
|
+
# --------------------------------------------------------------------------- #
|
|
61
|
+
@pytest.mark.benchmark(group="read-dat")
|
|
62
|
+
def test_read_dat_evutils(benchmark, benchmark_rounds, dat_file):
|
|
63
|
+
n = benchmark.pedantic(lambda: _read_all(dat_file), rounds=benchmark_rounds, iterations=1, warmup_rounds=1)
|
|
64
|
+
assert n > 0
|
|
65
|
+
benchmark.extra_info.update(library="evutils", n_events=n)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@pytest.mark.benchmark(group="read-dat")
|
|
69
|
+
def test_read_dat_expelliarmus(benchmark, benchmark_rounds, dat_file):
|
|
70
|
+
try:
|
|
71
|
+
from expelliarmus import Wizard
|
|
72
|
+
except ImportError as exc:
|
|
73
|
+
pytest.skip(f"expelliarmus not available: {exc}")
|
|
74
|
+
wizard = Wizard(encoding="dat")
|
|
75
|
+
n = benchmark.pedantic(lambda: len(wizard.read(str(dat_file))),
|
|
76
|
+
rounds=benchmark_rounds, iterations=1, warmup_rounds=1)
|
|
77
|
+
assert n > 0
|
|
78
|
+
benchmark.extra_info.update(library="expelliarmus", n_events=n)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@pytest.mark.benchmark(group="write-dat")
|
|
82
|
+
def test_write_dat_evutils(benchmark, benchmark_rounds, reference_events, tmp_path):
|
|
83
|
+
out = tmp_path / "out.dat"
|
|
84
|
+
benchmark.pedantic(lambda: _write(out, reference_events),
|
|
85
|
+
rounds=benchmark_rounds, iterations=1, warmup_rounds=1)
|
|
86
|
+
assert len(EventReader(out).read_all()) == len(reference_events)
|
|
87
|
+
benchmark.extra_info.update(library="evutils", n_events=len(reference_events))
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@pytest.mark.benchmark(group="write-dat")
|
|
91
|
+
def test_write_dat_expelliarmus(benchmark, benchmark_rounds, reference_events, tmp_path):
|
|
92
|
+
try:
|
|
93
|
+
from expelliarmus import Wizard
|
|
94
|
+
except ImportError as exc:
|
|
95
|
+
pytest.skip(f"expelliarmus not available: {exc}")
|
|
96
|
+
wizard = Wizard(encoding="dat")
|
|
97
|
+
out = tmp_path / "out.dat"
|
|
98
|
+
benchmark.pedantic(lambda: wizard.save(str(out), reference_events),
|
|
99
|
+
rounds=benchmark_rounds, iterations=1, warmup_rounds=1)
|
|
100
|
+
assert len(wizard.read(str(out))) == len(reference_events)
|
|
101
|
+
benchmark.extra_info.update(library="expelliarmus", n_events=len(reference_events))
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
# --------------------------------------------------------------------------- #
|
|
105
|
+
# AER
|
|
106
|
+
# --------------------------------------------------------------------------- #
|
|
107
|
+
@pytest.mark.benchmark(group="read-aer")
|
|
108
|
+
def test_read_aer_evutils(benchmark, benchmark_rounds, aer_file):
|
|
109
|
+
n = benchmark.pedantic(lambda: _read_all(aer_file), rounds=benchmark_rounds, iterations=1, warmup_rounds=1)
|
|
110
|
+
assert n > 0
|
|
111
|
+
benchmark.extra_info.update(library="evutils", n_events=n)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@pytest.mark.benchmark(group="write-aer")
|
|
115
|
+
def test_write_aer_evutils(benchmark, benchmark_rounds, aer_events, tmp_path):
|
|
116
|
+
out = tmp_path / "out.aer"
|
|
117
|
+
benchmark.pedantic(lambda: _write(out, aer_events),
|
|
118
|
+
rounds=benchmark_rounds, iterations=1, warmup_rounds=1)
|
|
119
|
+
benchmark.extra_info.update(library="evutils", n_events=len(aer_events))
|
|
@@ -17,16 +17,20 @@ FORMATS = ["evt3", "evt2", "evt21"]
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
@pytest.mark.parametrize("fmt", FORMATS)
|
|
20
|
-
def test_read_evutils(benchmark, real_event_files, fmt):
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
def test_read_evutils(benchmark, benchmark_rounds, real_event_files, fmt):
|
|
21
|
+
benchmark.group = f"read-{fmt}"
|
|
22
|
+
if fmt not in real_event_files or not real_event_files[fmt]:
|
|
23
|
+
pytest.skip(f"No files for format {fmt}")
|
|
24
|
+
ef = next((f for f in real_event_files[fmt] if 'hand' in f.path.name), real_event_files[fmt][0])
|
|
25
|
+
|
|
26
|
+
def decode():
|
|
27
|
+
total = 0
|
|
28
|
+
with EventReader(ef.path) as reader:
|
|
29
|
+
for chunk in reader:
|
|
30
|
+
total += len(chunk)
|
|
31
|
+
return total
|
|
32
|
+
|
|
33
|
+
n = benchmark.pedantic(decode, rounds=benchmark_rounds, iterations=1, warmup_rounds=1)
|
|
30
34
|
|
|
31
35
|
# Sanity: the benchmarked path decodes the expected number of events.
|
|
32
36
|
assert n == ef.count
|