diff --git a/image_analysis/rotation_indexer/RotationIndexer.cpp b/image_analysis/rotation_indexer/RotationIndexer.cpp index 613766277..9b911ae3d 100644 --- a/image_analysis/rotation_indexer/RotationIndexer.cpp +++ b/image_analysis/rotation_indexer/RotationIndexer.cpp @@ -13,6 +13,7 @@ #include #include #include +#include namespace { // Sub-cell override thresholds used in candidate selection to undo a spurious axis doubling: @@ -160,16 +161,32 @@ namespace { static_cast(x.GetIndexingThreads()), static_cast(x.GetRefineThreads())}); } + // The input key is kept as two independent 64-bit hashes of its bytes plus its length - a key + // holds every spot, so keeping it whole would cost megabytes per entry. + struct KeyDigest { + size_t n; + uint64_t fnv, std_hash; + bool operator==(const KeyDigest &) const = default; + }; + KeyDigest Digest(const std::vector &key) { + const std::string_view bytes(reinterpret_cast(key.data()), key.size() * sizeof(double)); + uint64_t fnv = 14695981039346656037ULL; // FNV-1a + for (const char c : bytes) + fnv = (fnv ^ static_cast(c)) * 1099511628211ULL; + return {key.size(), fnv, std::hash{}(bytes)}; + } + struct IndexingMemo { std::mutex m; - std::vector, RotationIndexer::IndexingOutcome>> entries; + std::vector> entries; }; IndexingMemo &Memo() { static IndexingMemo memo; return memo; } - // A run asks a handful of distinct questions at most; the oldest go first. - constexpr size_t MAX_INDEXING_MEMOS = 32; + // A run on data that index poorly asks well over a hundred questions (every rung of the spot-budget + // ladder, in every pass and probe), and a later pass repeats a probe's; the oldest go first. + constexpr size_t MAX_INDEXING_MEMOS = 1024; // Bitwise comparison of what a recomputation gave against what was kept. bool SameOutcome(const RotationIndexer::IndexingOutcome &a, const RotationIndexer::IndexingOutcome &b) { @@ -229,7 +246,7 @@ void RotationIndexer::RunIndexing() { if (!axis_) return; - const std::vector key = InputKey(); + const KeyDigest key = Digest(InputKey()); std::optional kept; { auto &memo = Memo();