From 5282dd6199d44a979ee1a683d64bf32ed7108ea4 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 7 Oct 2026 11:58:39 +0200 Subject: [PATCH] RotationScaleMerge::RunArm: free the fulls before growing them When a chain needs more fulls than the arrays hold, fulls and fulls_staging are released before the resize. The gather overwrites every field, so growing in place only copied the previous chain's records into the new allocation to be overwritten. The expected saving (a few tenths of a second on 8tyy) is below the run-to-run noise of the wall clock: 8tyy median of 3, 127.0 s without vs 129.6 s with, under different machine load. 8qaw max RSS 21.9 -> 21.7 GB. p.mtz md5-identical to rc175 on myoglobin, cytochrome C (also at -N 4 and -N 8), thaumatin, 8a1a, 8tyy, 9gdj and 8qaw. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01SVmAWnzCmRKAXVUCdc4iNi --- image_analysis/scale_merge/RotationScaleMerge.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/image_analysis/scale_merge/RotationScaleMerge.cpp b/image_analysis/scale_merge/RotationScaleMerge.cpp index be65e5678..5312363a9 100644 --- a/image_analysis/scale_merge/RotationScaleMerge.cpp +++ b/image_analysis/scale_merge/RotationScaleMerge.cpp @@ -6476,7 +6476,13 @@ RotationScaleMerge::Result RotationScaleMerge::RunArm(bool scale_partials, bool // resize, not assign: the gather below writes every field of every full, so zeroing 80 bytes // each first is a few hundred megabytes of pure write traffic per chain. The staging arrays are - // members for the same reason. + // members for the same reason. Nothing in them survives the gather either, so when they have + // to grow they are freed first: growing in place would copy the previous chain's records into + // the new allocation only for the gather to overwrite them. + if (static_cast(nf) > fulls.capacity()) { + fulls = {}; + fulls_staging = {}; + } fulls.resize(nf); FullsStaging &st = fulls_staging; st.Resize(nf);