GPU memory over the run: FFT indexers given back after the last indexing; speculative probe takes turns with the merge on a small card

- IndexerThreadPool::ReleaseIndexers(): each worker drops the indexers it has
  built (once its current frame is done) and the allocation pool is trimmed, so
  their memory goes back to the card, not only to the pool. A later frame builds
  them again, as on first use. A rotation pass calls it once its first pass is
  done and again when the leftover-lattice census - the last of its indexing -
  ends. Measured on the RTX 5080: the 1.24 GB (pre-pass) / 0.62 GB (later
  passes) the pass's pool held through the image pass and the scaling is gone;
  4nwv's pre-pass image pass peaks 5.97 instead of 7.18 GB of device memory.
- GPUMerge: the main line holds one through ScaleMergeAndSymmetry. The
  speculative geometry probe (GPUWorkBeside(after_merges=true)) waits for it on
  a card below the take-turns size (12 GB), where the probe's FFT indexers and
  image workers beside the merge's arrays would overfill the card - on a
  Windows (WDDM) card that does not fail an allocation but pages it and crawls.
  The merge waits for nothing, so nothing the merge waits on (the rotation-scale
  walk's probes) can wait in a circle with it. No change on a 16 GB card.

Output unchanged: p.hkl byte-identical on cytc_x10sa, myob_x10sa, 4nwv and
8qaw on this card; also identical with the card's total read as 8.55 GB
(10 / 9 image workers instead of 16) and with 4 image workers, so the worker
count does not change the result.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
leonarski_fandClaude Opus 5.5 committed 2026-10-15 11:39:19 +02:00
1 parent 640b2e464a
commit 1c3a2e202c
7 files changed
+174 -10

No files matched your search

+14 -3
View File
@@ -33,7 +33,7 @@ namespace {
// thread to wait until none of one kind is.
std::mutex gpu_work_m;
std::condition_variable gpu_work_changed;
int gpu_work_beside_n = 0, gpu_image_passes_n = 0;
int gpu_work_beside_n = 0, gpu_image_passes_n = 0, gpu_merges_n = 0;
// A card too small for a probe pass beside the main line's image pass, or beside another probe pass:
// measured on a 16 Mpx detector, two of them together held 8.6 GB. On such a card a probe pass waits,
@@ -56,10 +56,12 @@ namespace {
}
}
GPUWorkBeside::GPUWorkBeside() {
GPUWorkBeside::GPUWorkBeside(bool after_merges) {
std::unique_lock lock(gpu_work_m);
if (take_turns())
gpu_work_changed.wait(lock, [] { return gpu_image_passes_n == 0 && gpu_work_beside_n == 0; });
gpu_work_changed.wait(lock, [after_merges] {
return gpu_image_passes_n == 0 && gpu_work_beside_n == 0 && (!after_merges || gpu_merges_n == 0);
});
++gpu_work_beside_n;
}
@@ -83,6 +85,15 @@ GPUImagePass::~GPUImagePass() {
remove(gpu_image_passes_n);
}
GPUMerge::GPUMerge() {
std::lock_guard lock(gpu_work_m);
++gpu_merges_n;
}
GPUMerge::~GPUMerge() {
remove(gpu_merges_n);
}
void wait_for_gpu_image_passes() {
std::unique_lock lock(gpu_work_m);
gpu_work_changed.wait(lock, [] { return gpu_image_passes_n == 0; });