From 6f361ccde57d3df41fb38efa6a3e919e625b3d8f Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Sun, 18 Oct 2026 08:42:02 +0200 Subject: [PATCH] HostWorkerPool: half the budget, MR placements reserve 16 B per grid point, output unchanged Without a GPU (macOS), rc176's worker pool - 1/3 of the 12.9 GB budget on a 16 GB Mac - let only two molecular-replacement placements run at once, as each reserved 32 B per grid point (2.1 GB on 4nwv) against a measured ~0.95 GB. MR rescoring went from 38.6 s to 69 s and 4nwv's wall time from 402 s (budget off) to 444 s. On the M6 Mac mini (16 GB), 4nwv, two runs each in alternating order on a quiet machine: - old build 234774ff0: 418.4 s, 20.0-21.3 GiB peak footprint, 576-682k swapouts - rc176 as shipped: 444.2 s, 14.5-15.2 GiB, 39-66k swapouts - this change: 402.4 s, 15.5-15.8 GiB, 66-93k swapouts - budget switched off: 401.7 s, 21.8-23.3 GiB, 268-433k swapouts 9zlo/9s02/9gjx: 71.9/79.0/82.8 s (old build 73.6/82.2/83.6), no swap. p.hkl byte-identical in every run: the pool decides only what runs at once. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_018My7tqt8a4LyKKjP3FhScT --- common/HostMemory.h | 2 +- image_analysis/structure_refinement/ModelGrid.h | 3 +++ image_analysis/structure_refinement/MolecularReplacement.cpp | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/common/HostMemory.h b/common/HostMemory.h index d016ddb58..07dae951b 100644 --- a/common/HostMemory.h +++ b/common/HostMemory.h @@ -22,7 +22,7 @@ size_t DefaultHostMemoryBudget(); // The share of the budget that the large per-worker buffers of parallel steps - a translation function's // grids, a null replicate's model maps - may hold at once. The rest is what the run holds beside them: // its reflections, its merge, the detector-sized arrays. -constexpr double HOST_WORKER_POOL_FRACTION = 1.0 / 3.0; +constexpr double HOST_WORKER_POOL_FRACTION = 0.5; // One pool for those buffers, process-wide. A worker reserves its bytes before it makes them and hands // them back when it is done; one that would take the pool past its size waits until others have handed diff --git a/image_analysis/structure_refinement/ModelGrid.h b/image_analysis/structure_refinement/ModelGrid.h index 96f647292..b6075a999 100644 --- a/image_analysis/structure_refinement/ModelGrid.h +++ b/image_analysis/structure_refinement/ModelGrid.h @@ -36,3 +36,6 @@ size_t ModelGridPoints(const gemmi::UnitCell &cell, const gemmi::SpaceGroup *sg, // and the bulk-solvent mask grids, and for each of them its transform's input copy, spectrum and coefficients, // with the two made at once (ModelValidation's compute_model_factors). constexpr size_t MODEL_FACTORS_BYTES_PER_GRID_POINT = 32; +// What a molecular-replacement placement's structure factors and rigid body hold on the CPU at their peak, per +// point of that grid: measured at under half of the above. +constexpr size_t MODEL_PLACEMENT_BYTES_PER_GRID_POINT = 16; diff --git a/image_analysis/structure_refinement/MolecularReplacement.cpp b/image_analysis/structure_refinement/MolecularReplacement.cpp index 53af8ec8c..5d976310f 100644 --- a/image_analysis/structure_refinement/MolecularReplacement.cpp +++ b/image_analysis/structure_refinement/MolecularReplacement.cpp @@ -2777,7 +2777,7 @@ MolecularReplacementResult search_model(const SearchModel &model, const std::vec // gigabyte or more of grids on a large cell, so each reserves them against the host's worker // pool first (HostWorkerPool), as a null replicate does. const size_t placement_bytes = get_gpu_count() == 0 - ? MODEL_FACTORS_BYTES_PER_GRID_POINT * ModelGridPoints(cell, &sg, d_min) + ? MODEL_PLACEMENT_BYTES_PER_GRID_POINT * ModelGridPoints(cell, &sg, d_min) : 0; for (First *f : to_refine) running.push_back(std::async(std::launch::async, [&, f] {