rugnux: keep a pass's per-image reflections in large blocks

The whole-run passes retain every frame's integrated reflections until scaling is done - thousands
of vectors of a few megabytes each, allocated by the image workers in the allocator's per-thread
arenas. When a pass hands them back, most of that memory stays in those arenas as holes, and the
next pass's workers (new threads) do not reuse it, so on a fine-sliced long axis gigabytes of freed
reflections were carried to the end of the run.

IndexAndRefine now copies each retained frame's reflections into a ReflectionArena: 64 MiB blocks,
each its own mapping, carved by a bump pointer and returned to the system in one piece when the
last vector in them is gone. IntegrationOutcome::reflections becomes a std::vector with an allocator
that uses the arena when given one and plain new/delete otherwise (copies go to the heap), so the
read sites are unchanged; the few functions that took the vector by type now take a span.

No arithmetic changes; merged output byte-identical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013nW6FNRP1bBJJ8pfHiByAT
This commit is contained in:
2026-09-20 18:45:17 +02:00
co-authored by Claude Opus 5
parent bb55715d28
commit ca9a21c45e
11 changed files with 143 additions and 14 deletions
+2 -1
View File
@@ -303,9 +303,10 @@ CrystalLattice ApplyReindex(const CrystalLattice &latt, const std::optional<std:
return latt.Multiply(gemmi::Mat33(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8]));
}
template <class ReflectionContainer>
bool ReadReflectionsFromGroup(HDF5Object &file,
const std::string &image_group_name,
std::vector<Reflection> &reflections,
ReflectionContainer &reflections,
const std::optional<std::array<int32_t, 9>> &reindex) {
if (!file.Exists("/entry/reflections") || !file.Exists(image_group_name))
return false;