Commit Graph
11 Commits
Author SHA1 Message Date
kferjaoui 47d89446e2 CUDA: C++17 cleanup of ClusterFinderCUDA
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
- 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
kferjaoui 0c3c45e653 CUDA: unify GPU code under aare::cuda
Build on RHEL8 / build (push) Successful in 3m55s
Build on RHEL9 / build (push) Successful in 4m8s
Run tests using data on local RHEL8 / build (push) Successful in 4m55s
- aare::device -> aare::cuda::detail; drivers, RAII helpers,
  StreamContext* moved into aare::cuda(::detail)
- Algo contract: add compute_type, assert floating point
- LaunchParams::nSigma uses compute_type
- test: use FastPedestal in the manual route
2026-09-28 11:47:55 +02:00
kferjaoui d9bead2a07 Port the frozen and CUDA finders to FastPedestal
Build on RHEL8 / build (push) Successful in 3m38s
Build on RHEL9 / build (push) Successful in 3m49s
Run tests using data on local RHEL8 / build (push) Successful in 4m46s
- main moved ClusterFinder to FastPedestal and dropped Pedestal's
  push_fast/get_sum/get_sum2, which ClusterFinderFrozen and both CUDA
  drivers still called.

- Move all three to FastPedestal. Its uniform sample count is what the
  CUDA kernel already assumes, and matching ClusterFinder keeps CPU and
  GPU warm-up identical, which ClusterFinderFrozen exists to verify.
  FastPedestal gains get_sum/get_sum2 to de-interleave its internal
  Entry{sum,sum2} for the CUDA upload.

- Also expose min_pedestal_samples on these constructors and factories,
  make the factories keyword-only after image_size. Same API in C++ and Python.
2026-09-23 15:54:16 +02:00
kferjaouiandClaude Fable 5.1 272b483c6c CUDA: split the cluster finder into algorithm, stream context and driver
ClusterFinderCUDA mixed three things: which kernel runs and what device
state it needs, the per-stream buffers, and the batching pipeline. A
second algorithm meant a second copy of all of it. The pieces are now
separate and the driver is templated on the algorithm.

  cuda::FixedWindow  (clusterfinder_algo.cuh)  the fixed-size window
      search: DeviceState pointer bundle, launch(), and the pedestal
      transforms. Stateless; every pointer is supplied by the caller,
      so external code can drive the kernel on its own memory and
      stream without touching the driver.
  StreamContext<Algo>  one stream's buffers, RAII, non-movable.
  ClusterFinderCUDA<Algo>  the pipeline, unchanged in behaviour.

no_2x2_cluster moves to Cluster.hpp so the kernel and algorithm headers
no longer drag in ClusterFinder.hpp. The Python factory gains
algorithm="fixed_window"; memory stays internal.

Kernel SASS identical to before. Positions identical against
ClusterFinderFrozen for 3x3, 5x5, 9x9 (stream and graph finders). New
Catch2 test drives FixedWindow::launch on raw cudaMalloc buffers and
requires exact agreement with the driver.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 12:08:16 +02:00
kferjaoui 9921944772 CUDA: zero-copy collection, pipelined slots, optional kernel timing
Build on RHEL8 / build (push) Successful in 3m34s
Build on RHEL9 / build (push) Successful in 3m35s
Run tests using data on local RHEL8 / build (push) Successful in 4m13s
Host-side pipeline work ported from the benchmark branch. The kernel is
unchanged, so cluster results are identical.

  - collect_view()/BatchView: read clusters in place from the pinned D2H
    buffer instead of copying one ClusterVector per frame. The view is
    released back to the finder, so keep nothing that borrows it.
  - reserve_output_slots(), chunk_size_for(): pre-pin the output slots and
    size a batch to fit one.
  - find_cluster_views_batched_iter(): submits chunk i+1 before collecting
    chunk i.
  - time_kernels, default off. avg_kernel_time_ms() returns NaN unless
    enabled, and always for the Graph variant.
  - n_streams defaults to 4 everywhere.

ClusterFinderCUDA.ipynb cut to CPU MT vs batched CUDA plus a cluster-set
diff, and it now reports peak clusters/frame.

Removed src/ClusterFinderCUDA{,_old}.test.cu and src/Makefile (early C++
benchmarks, never in the CMake build), the perf and Frozen-vs-CUDA
notebooks, and helper.py.
2026-09-02 12:20:38 +02:00
kferjaoui 1bf317f42a CUDA: double-precision device path, local-max fix, pedestal introspection
- DEVICE_PED_TYPE for device pedestal/variance (shipped double/double to match
    the double CPU ClusterFinder).
- Local-max suppression in Test 1/Test 3: non-peak pixels no longer store or
    update, mirroring ClusterFinder's `value < max -> continue`.
- device_pedestal()/device_noise() accessors (+ bindings) for the in-kernel
    decision-time pedestal.
2026-08-03 11:39:02 +02:00
kferjaoui 5922c73c07 feat(ClusterFinderCUDA): async submit_batch/collect API
Build on RHEL8 / build (push) Successful in 3m16s
Build on RHEL9 / build (push) Successful in 3m26s
Run tests using data on local RHEL8 / build (push) Successful in 9m42s
- Eliminate the ~200–300 µs inter-batch idle gap by allowing two batches
to be in-flight simultaneously:
  - submit_batch() enqueues H2D+kernel+D2H without blocking
  - collect() syncs via cudaEventSynchronize (not
  cudaStreamSynchronize) so a queued second batch runs uninterrupted.

- Two ping-pong output slots (NUM_SLOTS=2) with per-slot pinned buffers
and cudaEventDisableTiming sync events.
- find_clusters_batched() keeps its direct implementation.

* Measured: 0.026 -> 0.022 ms/frame (~18%).
2026-05-28 16:23:37 +02:00
kferjaoui 6a12e3de24 Refactor ClusterFinderCUDA
Build on RHEL9 / build (push) Successful in 3m22s
Build on RHEL8 / build (push) Successful in 3m28s
Run tests using data on local RHEL8 / build (push) Successful in 3m37s
Rework the multi-stream pipeline to eliminate per-frame sync barriers and
fix the D2H staging architecture.

Sync reduction:
- Replace one cudaStreamSynchronize per frame with one per stream per batch,
  cutting synchronisation calls from O(n_frames x n_streams) to O(n_streams)
- Introduce a unified per-frame D2H output layout [uint32_t count | clusters[max]]
  stored in a single class-level lazy-allocated pinned pool (h_output_pinned),
  replacing the per-stream separate cluster/count device buffers
- Move CUDA event pool from per-stream fixed-size to per-frame-slot lazy-allocated,
  enabling correct kernel timing across any batch size

Pinned H2D without CPU-side copy:
- Add register_input_buffer(ptr, bytes) / unregister_input_buffer() wrapping
  cudaHostRegister so callers can pin their existing batch buffer once; all
  find_clusters_batched() slices then transfer at DMA speed (~22 GB/s) instead
  of ~15 GB/s for pageable, with no extra memcpy or WC-memory penalty

Result (RTX 4090, 400x400 uint16, 3x3 clusters, batch=2000, 5 streams):
  Before: ~34 µs/frame  ->  After: ~28 µs/frame  (−18 %)
2026-05-18 16:30:13 +02:00
kferjaoui 34e69a8065 Add per-frame kernel timing via CUDA events
Build on RHEL8 / build (push) Successful in 3m13s
Build on RHEL9 / build (push) Successful in 3m37s
Run tests using data on local RHEL8 / build (push) Successful in 3m51s
2026-04-28 13:09:25 +02:00
kferjaoui a086cbb897 Format CUDA cluster finder files
Build on RHEL8 / build (push) Successful in 3m13s
Build on RHEL9 / build (push) Successful in 3m34s
Run tests using data on local RHEL8 / build (push) Successful in 3m48s
2026-04-27 11:27:47 +02:00
kferjaoui e894bdac9b Add Python bindings for CUDA cluster finder
Build on RHEL8 / build (push) Successful in 2m50s
Build on RHEL9 / build (push) Successful in 2m57s
Run tests using data on local RHEL8 / build (push) Successful in 3m38s
- Add bind_ClusterFinderCUDA.hpp with pybind11 bindings for
  ClusterFinderCUDA
- Build CUDA bindings as separate _aare_cuda.so to avoid
  segfaults from mixing nvcc and gcc compiled code in the
  same shared object
- Re-export CUDA classes onto _aare in __init__.py so user
  code uses `from aare import ClusterFinderCUDA` regardless
  of which .so hosts the class
- Factory in ClusterFinder.py selects backend; RuntimeError
  if GPU requested on CPU-only build
- Update python/CMakeLists.txt: _aare_cuda module gated
  behind AARE_CUDA and AARE_PYTHON_BINDINGS
- Add validation notebook: ~20x speedup vs sequential ClusterFinder
2026-04-23 11:43:40 +02:00