mirror of
https://github.com/slsdetectorgroup/aare.git
synced 2026-10-31 19:11:28 +01:00
- std::array for per-slot state; std::exchange in BatchView::steal - [[nodiscard]]/noexcept on the public API and release path - cuda_check moved to aare::cuda::detail (was reserved __cuda_check) - _v type traits; drop redundant std::move and `using namespace aare` - Add pytest for BatchView slot release
81 lines
2.5 KiB
Python
81 lines
2.5 KiB
Python
# SPDX-License-Identifier: MPL-2.0
|
|
import numpy as np
|
|
import pytest
|
|
|
|
from aare import ClusterFinderCUDA, _cuda_available, find_cluster_views_batched_iter
|
|
|
|
pytestmark = pytest.mark.skipif(
|
|
not _cuda_available(), reason="aare built without AARE_CUDA")
|
|
|
|
SHAPE = (32, 32)
|
|
BATCH = 4
|
|
# Pixel that gets a photon in every data frame, away from the border.
|
|
HIT = (16, 16)
|
|
|
|
|
|
@pytest.fixture
|
|
def cf():
|
|
cf = ClusterFinderCUDA(SHAPE, n_streams=2, min_pedestal_samples=10)
|
|
rng = np.random.default_rng(42)
|
|
for _ in range(20):
|
|
cf.push_pedestal_frame(
|
|
rng.normal(1000, 5, SHAPE).astype(np.uint16))
|
|
return cf
|
|
|
|
|
|
@pytest.fixture
|
|
def frames():
|
|
rng = np.random.default_rng(7)
|
|
f = rng.normal(1000, 5, (BATCH, *SHAPE)).astype(np.uint16)
|
|
f[:, HIT[0], HIT[1]] = 3000
|
|
return f
|
|
|
|
|
|
def test_collect_view_exposes_batch(cf, frames):
|
|
tok = cf.submit_batch(frames, first_frame=100)
|
|
with cf.collect_view(tok) as v:
|
|
assert v.valid
|
|
assert v.n_frames == BATCH
|
|
assert v.first_frame == 100
|
|
assert all(v.count(i) >= 1 for i in range(BATCH))
|
|
assert not v.valid
|
|
|
|
|
|
def test_released_view_frees_its_slot(cf, frames):
|
|
# Cycles both slots twice. pybind11 move-constructs every returned
|
|
# BatchView, so a move that drops the slot index leaves the slot held
|
|
# forever and the third submit_batch() throws.
|
|
for i in range(2 * 2):
|
|
tok = cf.submit_batch(frames, first_frame=i * BATCH)
|
|
v = cf.collect_view(tok)
|
|
v.release()
|
|
assert not v.valid
|
|
|
|
|
|
def test_dropped_view_frees_its_slot(cf, frames):
|
|
# The destructor releases, so a view that is never bound is harmless.
|
|
for i in range(2 * 2):
|
|
tok = cf.submit_batch(frames, first_frame=i * BATCH)
|
|
cf.collect_view(tok)
|
|
|
|
|
|
def test_held_view_blocks_its_slot(cf, frames):
|
|
held = cf.collect_view(cf.submit_batch(frames))
|
|
# The other slot is still free.
|
|
with cf.collect_view(cf.submit_batch(frames)):
|
|
pass
|
|
with pytest.raises(RuntimeError, match="held by a BatchView"):
|
|
cf.submit_batch(frames)
|
|
held.release()
|
|
with cf.collect_view(cf.submit_batch(frames)):
|
|
pass
|
|
|
|
|
|
def test_views_batched_iter_pipelines_all_chunks(cf, frames):
|
|
data = np.concatenate([frames] * 3)
|
|
seen = []
|
|
for v in find_cluster_views_batched_iter(cf, data, first_frame=10,
|
|
chunk=BATCH):
|
|
seen.append((v.first_frame, v.n_frames))
|
|
assert seen == [(10, BATCH), (10 + BATCH, BATCH), (10 + 2 * BATCH, BATCH)]
|