From 3ccb97e31bd2274f050889f11e195615fcab92ab Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Sat, 8 Aug 2026 15:33:24 +0200 Subject: [PATCH] Adaptive spot finder: pin the per-ring host buffers The GPU engine copies six small per-ring arrays back to the host every frame - the clipped raw sum/sum2/count that the threshold is computed from, and the plain corrected sum/sum2/count that become the azimuthal profile. They were plain std::vectors, so the copies landed in pageable memory, and a device-to-host copy into pageable memory blocks the calling thread until it has completed whatever stream it was issued on. The profile snapshot sits between the plain pass and the two sigma-clip passes, so Detect() stopped there and the device then sat idle while the host caught up and enqueued the rest. Register them, as AzIntEngineGPU already does with its own, and the copies are genuinely asynchronous. Measured on a 4.5 Mpixel frame: 0.647 -> 0.621 ms per frame. Nothing else changes - the spot list and the profile are unaffected. Co-Authored-By: Claude Opus 5 (1M context) --- image_analysis/spot_finding/AdaptiveSpotFinderGPU.cu | 6 ++++++ image_analysis/spot_finding/AdaptiveSpotFinderGPU.h | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/image_analysis/spot_finding/AdaptiveSpotFinderGPU.cu b/image_analysis/spot_finding/AdaptiveSpotFinderGPU.cu index a20caa01..8ec5328f 100644 --- a/image_analysis/spot_finding/AdaptiveSpotFinderGPU.cu +++ b/image_analysis/spot_finding/AdaptiveSpotFinderGPU.cu @@ -191,6 +191,12 @@ AdaptiveSpotFinderGPU::AdaptiveSpotFinderGPU(const AzimuthalIntegrationMapping & prof_sum(nbins), prof_sum2(nbins), prof_count(nbins), + host_sum_reg(host_sum), + host_sum2_reg(host_sum2), + host_count_reg(host_count), + prof_sum_reg(prof_sum), + prof_sum2_reg(prof_sum2), + prof_count_reg(prof_count), extractor(static_cast(in_mapping.GetWidth()), static_cast(in_mapping.GetHeight()), std::move(in_stream)), last_profile(in_mapping) { diff --git a/image_analysis/spot_finding/AdaptiveSpotFinderGPU.h b/image_analysis/spot_finding/AdaptiveSpotFinderGPU.h index 5eecba20..f4beaa5b 100644 --- a/image_analysis/spot_finding/AdaptiveSpotFinderGPU.h +++ b/image_analysis/spot_finding/AdaptiveSpotFinderGPU.h @@ -80,6 +80,18 @@ class AdaptiveSpotFinderGPU : public ImageSpotFinder { std::vector prof_sum2; // plain corrected sum^2 } std::vector prof_count; // plain pixel count } + // Every per-ring array above is a device-to-host copy once per frame. A D2H copy into PAGEABLE + // memory blocks the host until it completes, whatever stream it was issued on - which would stall + // Detect() between the plain pass and the clip passes, with the device then idle while the host + // enqueues them. Pinning the destinations makes the copies genuinely asynchronous, as the + // azimuthal-integration engine already does with its own. + CudaRegisteredVector host_sum_reg; + CudaRegisteredVector host_sum2_reg; + CudaRegisteredVector host_count_reg; + CudaRegisteredVector prof_sum_reg; + CudaRegisteredVector prof_sum2_reg; + CudaRegisteredVector prof_count_reg; + SpotExtractorGPU extractor; // builds the spots from gpu_strong without it leaving the device AzimuthalIntegrationProfile last_profile; // filled every Run(), retrievable via GetProfile()