rugnux: build the first-pass analysis engine once, not per image
The first-pass spot cache constructed an MXAnalysisWithoutFPGA and an AzimuthalIntegrationProfile inside the per-image lambda, so every cache miss allocated a CUDA stream, the preprocessing buffer, the spot finder, the azimuthal integrator and the Bragg engine, used them for one frame, and freed them again - hundreds of times, serially, on the --redo-rotation-spots path. Both worker loops already hoist the same object out of their loop; only this path did not. Build them once for the whole first pass, and only when spots actually have to be found (with --reuse-rotation-spots there is nothing to allocate). Reuse is safe because every azimuthal-integration path - CPU, GPU and the fused adaptive engine - clears the caller's profile before adding to it, so each frame's output is unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+13
-4
@@ -506,6 +506,18 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b
|
||||
// validation set; re-finding is expensive on the --redo-rotation-spots path). Accessed only
|
||||
// from single-threaded sections (the scheme feed and the validation loop), so no locking.
|
||||
std::map<int, std::vector<SpotToSave>> spot_cache;
|
||||
// One analysis engine for the whole first pass. Constructing it allocates a CUDA stream and a
|
||||
// full set of GPU buffers (preprocessing, spot finding, azimuthal integration, Bragg
|
||||
// integration) - far more work than analysing a frame - so building it per image made
|
||||
// --redo-rotation-spots pay for hundreds of them, serially. Only needed when spots have to be
|
||||
// found; this section is single-threaded, so one engine is enough.
|
||||
std::unique_ptr<MXAnalysisWithoutFPGA> analysis;
|
||||
std::unique_ptr<AzimuthalIntegrationProfile> profile;
|
||||
if (!reuse_spots) {
|
||||
analysis = std::make_unique<MXAnalysisWithoutFPGA>(experiment_, mapping, pixel_mask_, *indexer,
|
||||
/*enable_fused_adaptive_gpu=*/true);
|
||||
profile = std::make_unique<AzimuthalIntegrationProfile>(mapping);
|
||||
}
|
||||
auto get_spots = [&](int ordinal) -> const std::vector<SpotToSave> & {
|
||||
auto it = spot_cache.find(ordinal);
|
||||
if (it != spot_cache.end())
|
||||
@@ -519,16 +531,13 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b
|
||||
DataMessage m{};
|
||||
m.number = ordinal;
|
||||
m.original_number = image_idx;
|
||||
MXAnalysisWithoutFPGA analysis(experiment_, mapping, pixel_mask_, *indexer,
|
||||
/*enable_fused_adaptive_gpu=*/true);
|
||||
AzimuthalIntegrationProfile profile(mapping);
|
||||
auto first_pass = config_.spot_finding;
|
||||
first_pass.indexing = false;
|
||||
first_pass.quick_integration = false;
|
||||
m.image = img->image;
|
||||
if (dataset->efficiency.size() > image_idx)
|
||||
m.image_collection_efficiency = dataset->efficiency[image_idx];
|
||||
analysis.Analyze(m, profile, first_pass);
|
||||
analysis->Analyze(m, *profile, first_pass);
|
||||
spots = std::move(m.spots);
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
|
||||
Reference in New Issue
Block a user