Skip to content

Commit 2980e60

Browse files
perf: use vector instead of hash map for ProcessPendingInstantSendLocks
The 'pend' local variable in ProcessPendingInstantSendLocks was previously using the same data structure as pendingInstantSendLocks (a hash map). However, once we're in the processing step, we only iterate sequentially through the locks - there are no hash-based lookups. This commit changes 'pend' to use std::vector for better performance: - Improved cache locality with contiguous memory layout - Better CPU prefetching during iteration (3x through the data) - Eliminates hash map overhead (bucket allocation, pointer chasing) - Filtering step uses build-new-vector approach to maintain O(n) The typical case processes up to 32 locks, making the vector's sequential access pattern ideal for modern CPU cache hierarchies.
1 parent 5c6e98e commit 2980e60

File tree

2 files changed

+14
-11
lines changed

2 files changed

+14
-11
lines changed

src/instantsend/instantsend.cpp

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ MessageProcessingResult CInstantSendManager::ProcessMessage(NodeId from, std::st
174174

175175
instantsend::PendingState CInstantSendManager::ProcessPendingInstantSendLocks()
176176
{
177-
decltype(pendingInstantSendLocks) pend;
177+
std::vector<std::pair<uint256, instantsend::PendingISLockFromPeer>> pend;
178178
instantsend::PendingState ret;
179179

180180
if (!IsInstantSendEnabled()) {
@@ -189,14 +189,15 @@ instantsend::PendingState CInstantSendManager::ProcessPendingInstantSendLocks()
189189
// The keys of the removed values are temporaily stored here to avoid invalidating an iterator
190190
std::vector<uint256> removed;
191191
removed.reserve(maxCount);
192+
pend.reserve(maxCount);
192193

193194
for (const auto& [islockHash, nodeid_islptr_pair] : pendingInstantSendLocks) {
194195
// Check if we've reached max count
195196
if (pend.size() >= maxCount) {
196197
ret.m_pending_work = true;
197198
break;
198199
}
199-
pend.emplace(islockHash, std::move(nodeid_islptr_pair));
200+
pend.emplace_back(islockHash, std::move(nodeid_islptr_pair));
200201
removed.emplace_back(islockHash);
201202
}
202203

@@ -222,24 +223,25 @@ instantsend::PendingState CInstantSendManager::ProcessPendingInstantSendLocks()
222223
if (!badISLocks.empty()) {
223224
LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- doing verification on old active set\n", __func__);
224225

225-
// filter out valid IS locks from "pend"
226-
for (auto it = pend.begin(); it != pend.end();) {
227-
if (!badISLocks.count(it->first)) {
228-
it = pend.erase(it);
229-
} else {
230-
++it;
226+
// filter out valid IS locks from "pend" - keep only bad ones
227+
std::vector<std::pair<uint256, instantsend::PendingISLockFromPeer>> filteredPend;
228+
filteredPend.reserve(badISLocks.size());
229+
for (auto& p : pend) {
230+
if (badISLocks.contains(p.first)) {
231+
filteredPend.push_back(std::move(p));
231232
}
232233
}
234+
233235
// Now check against the previous active set and perform banning if this fails
234-
ProcessPendingInstantSendLocks(llmq_params, dkgInterval, /*ban=*/true, pend, ret.m_peer_activity);
236+
ProcessPendingInstantSendLocks(llmq_params, dkgInterval, /*ban=*/true, filteredPend, ret.m_peer_activity);
235237
}
236238

237239
return ret;
238240
}
239241

240242
Uint256HashSet CInstantSendManager::ProcessPendingInstantSendLocks(
241243
const Consensus::LLMQParams& llmq_params, int signOffset, bool ban,
242-
const Uint256HashMap<instantsend::PendingISLockFromPeer>& pend,
244+
const std::vector<std::pair<uint256, instantsend::PendingISLockFromPeer>>& pend,
243245
std::vector<std::pair<NodeId, MessageProcessingResult>>& peer_activity)
244246
{
245247
CBLSBatchVerifier<NodeId, uint256> batchVerifier(false, true, 8);

src/instantsend/instantsend.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <atomic>
2121
#include <unordered_map>
2222
#include <unordered_set>
23+
#include <vector>
2324

2425
class CBlockIndex;
2526
class CChainState;
@@ -122,7 +123,7 @@ class CInstantSendManager final : public instantsend::InstantSendSignerParent
122123
EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry);
123124

124125
Uint256HashSet ProcessPendingInstantSendLocks(const Consensus::LLMQParams& llmq_params, int signOffset, bool ban,
125-
const Uint256HashMap<instantsend::PendingISLockFromPeer>& pend,
126+
const std::vector<std::pair<uint256, instantsend::PendingISLockFromPeer>>& pend,
126127
std::vector<std::pair<NodeId, MessageProcessingResult>>& peer_activity)
127128
EXCLUSIVE_LOCKS_REQUIRED(!cs_nonLocked, !cs_pendingLocks, !cs_pendingRetry);
128129
MessageProcessingResult ProcessInstantSendLock(NodeId from, const uint256& hash,

0 commit comments

Comments
 (0)