Files
aare/python/tests/test_ClusterFinderCUDA.py
T
kferjaoui 47d89446e2
Build on RHEL8 / build (push) Successful in 3m58s
Build on RHEL9 / build (push) Successful in 4m8s
Run tests using data on local RHEL8 / build (push) Failing after 5m13s
CUDA: C++17 cleanup of ClusterFinderCUDA
- 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
2026-10-01 15:17:03 +02:00

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)]