Skip to content

Commit

Permalink
Merge dashpay#6497: perf: use unordered_set / unordered_map where ord…
Browse files Browse the repository at this point in the history
…er isn't relevant

a04d178 perf: use unordered_set / unordered_map where order isn't relevant (pasta)

Pull request description:

  ## Issue being fixed or feature implemented
  We use std::set and std::map where we do not care about order, and it's mostly serves as a lookup. I couldn't find any instances in the code where we actually care about the ordering of these sets or maps.

  In this case, we should probably prefer using unordered_set and unordered_map.

  ## What was done?
  Converted these sets / maps into their unordered equivalent
  .
  ## How Has This Been Tested?
  Did a few quickbench to ensure there isn't some significant advantage to using the "worse" data structure at small sizes. these used sizes up to around 1000 instances per map / set, as this is the max number of connects we are every likely to see.

  set: https://quick-bench.com/q/ApPAGguzG2F9AnqM2GkgDAXCzX4
  map: https://quick-bench.com/q/PXDdF0HVGpiSmC9Hh5FUSTp0uJU

  In this we see there is never a reason to use set over unordered_set, assuming that order isn't important.

  Using unordered_map did show a small insertion regression for ~expected sizes on masternodes, but it appears that only 1 lookup will compensate for that overhead, and based on the codepaths, I expect more than 1 lookup per insertion.

  some perf results I have are here, show that this std::set usage is causing at least a measurable cpu usage.
  ```
  -    9.18%     0.00%  d-mncon      dashd                [.] CConnman::ThreadOpenMasternodeConnections(CDeterministicMNManager&, CMasternodeMetaMan&, CMasternodeSync&)::{lambda()#▒
     - CConnman::ThreadOpenMasternodeConnections(CDeterministicMNManager&, CMasternodeMetaMan&, CMasternodeSync&)::{lambda()#1}::operator()() const                                 ▒
        + 6.16% CConnman::IsMasternodeOrDisconnectRequested(CService const&)                                                                                                        ▒
        - 2.66% std::set<CService, std::less<CService>, std::allocator<CService> >::count(CService const&) const                                                                    ▒
           - std::_Rb_tree<CService, CService, std::_Identity<CService>, std::less<CService>, std::allocator<CService> >::find(CService const&) const                               ▒
              - 2.02% std::_Rb_tree<CService, CService, std::_Identity<CService>, std::less<CService>, std::allocator<CService> >::_M_lower_bound(std::_Rb_tree_node<CService> const▒
                 + 1.99% std::less<CService>::operator()(CService const&, CService const&) const                                                                                    ▒
              + 0.62% std::less<CService>::operator()(CService const&, CService const&) const
  ```

  ## Breaking Changes
  None

  ## Checklist:
    _Go over all the following points, and put an `x` in all the boxes that apply._
  - [ ] I have performed a self-review of my own code
  - [ ] I have commented my code, particularly in hard-to-understand areas
  - [ ] I have added or updated relevant unit/integration/functional/e2e tests
  - [ ] I have made corresponding changes to the documentation
  - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_

ACKs for top commit:
  UdjinM6:
    utACK a04d178
  knst:
    utACK a04d178

Tree-SHA512: 18a11d5ec55a0a96e4fa41694e11de628b84a7819112eae47591803aa0a8729bde38f8b9d93c91a52d3be481d68d1be7e03e130932c4480210e98cd35825a018
  • Loading branch information
PastaPastaPasta committed Dec 26, 2024
2 parents b2f8e07 + a04d178 commit 941e04e
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 36 deletions.
6 changes: 4 additions & 2 deletions src/llmq/dkgsession.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
#include <bls/bls.h>
#include <bls/bls_ies.h>
#include <bls/bls_worker.h>
#include <saltedhasher.h>
#include <sync.h>
#include <util/underlying.h>

#include <optional>
#include <unordered_set>

class CActiveMasternodeManager;
class CInv;
Expand Down Expand Up @@ -293,7 +295,7 @@ class CDKGSession
private:
std::vector<std::unique_ptr<CDKGMember>> members;
std::map<uint256, size_t> membersMap;
std::set<uint256> relayMembers;
std::unordered_set<uint256, StaticSaltedHasher> relayMembers;
BLSVerificationVectorPtr vvecContribution;
std::vector<CBLSSecretKey> m_sk_contributions;

Expand Down Expand Up @@ -382,7 +384,7 @@ class CDKGSession

public:
[[nodiscard]] CDKGMember* GetMember(const uint256& proTxHash) const;
[[nodiscard]] const std::set<uint256>& RelayMembers() const { return relayMembers; }
[[nodiscard]] const std::unordered_set<uint256, StaticSaltedHasher>& RelayMembers() const { return relayMembers; }
[[nodiscard]] const CBlockIndex* BlockIndex() const { return m_quorum_base_block_index; }
[[nodiscard]] const uint256& ProTx() const { return myProTxHash; }
[[nodiscard]] const Consensus::LLMQParams GetParams() const { return params; }
Expand Down
2 changes: 1 addition & 1 deletion src/llmq/quorums.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ void CQuorumManager::CheckQuorumConnections(CConnman& connman, const Consensus::
LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- llmqType[%d] h[%d] keeping mn quorum connections for quorum: [%d:%s]\n", __func__, ToUnderlying(llmqParams.type), pindexNew->nHeight, quorum->m_quorum_base_block_index->nHeight, quorum->m_quorum_base_block_index->GetBlockHash().ToString());
}
} else if (watchOtherISQuorums && !quorum->IsMember(myProTxHash)) {
std::set<uint256> connections;
std::unordered_set<uint256, StaticSaltedHasher> connections;
const auto& cindexes = utils::CalcDeterministicWatchConnections(llmqParams.type, quorum->m_quorum_base_block_index, quorum->members.size(), 1);
for (auto idx : cindexes) {
connections.emplace(quorum->members[idx]->proTxHash);
Expand Down
2 changes: 1 addition & 1 deletion src/llmq/signing_shares.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,7 @@ void CSigSharesManager::ProcessSigShare(PeerManager& peerman, const CSigShare& s
bool canTryRecovery = false;

// prepare node set for direct-push in case this is our sig share
std::set<NodeId> quorumNodes;
std::unordered_set<NodeId> quorumNodes;
if (!IsAllMembersConnectedEnabled(llmqType, m_sporkman) && sigShare.getQuorumMember() == quorum->GetMemberIndex(m_mn_activeman->GetProTxHash())) {
quorumNodes = connman.GetMasternodeQuorumNodes(sigShare.getLlmqType(), sigShare.getQuorumHash());
}
Expand Down
29 changes: 16 additions & 13 deletions src/llmq/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -653,12 +653,13 @@ uint256 DeterministicOutboundConnection(const uint256& proTxHash1, const uint256
return proTxHash2;
}

std::set<uint256> GetQuorumConnections(const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, const CSporkManager& sporkman,
gsl::not_null<const CBlockIndex*> pQuorumBaseBlockIndex, const uint256& forMember, bool onlyOutbound)
std::unordered_set<uint256, StaticSaltedHasher> GetQuorumConnections(
const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, const CSporkManager& sporkman,
gsl::not_null<const CBlockIndex*> pQuorumBaseBlockIndex, const uint256& forMember, bool onlyOutbound)
{
if (IsAllMembersConnectedEnabled(llmqParams.type, sporkman)) {
auto mns = GetAllQuorumMembers(llmqParams.type, dmnman, pQuorumBaseBlockIndex);
std::set<uint256> result;
std::unordered_set<uint256, StaticSaltedHasher> result;

for (const auto& dmn : mns) {
if (dmn->proTxHash == forMember) {
Expand All @@ -677,23 +678,25 @@ std::set<uint256> GetQuorumConnections(const Consensus::LLMQParams& llmqParams,
return GetQuorumRelayMembers(llmqParams, dmnman, pQuorumBaseBlockIndex, forMember, onlyOutbound);
}

std::set<uint256> GetQuorumRelayMembers(const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, gsl::not_null<const CBlockIndex*> pQuorumBaseBlockIndex,
const uint256& forMember, bool onlyOutbound)
std::unordered_set<uint256, StaticSaltedHasher> GetQuorumRelayMembers(const Consensus::LLMQParams& llmqParams,
CDeterministicMNManager& dmnman,
gsl::not_null<const CBlockIndex*> pQuorumBaseBlockIndex,
const uint256& forMember, bool onlyOutbound)
{
auto mns = GetAllQuorumMembers(llmqParams.type, dmnman, pQuorumBaseBlockIndex);
std::set<uint256> result;
std::unordered_set<uint256, StaticSaltedHasher> result;

auto calcOutbound = [&](size_t i, const uint256& proTxHash) {
// Relay to nodes at indexes (i+2^k)%n, where
// k: 0..max(1, floor(log2(n-1))-1)
// n: size of the quorum/ring
std::unordered_set<uint256, StaticSaltedHasher> r{};
if (mns.size() == 1) {
// No outbound connections are needed when there is one MN only.
// Also note that trying to calculate results via the algorithm below
// would result in an endless loop.
return std::set<uint256>();
return r;
}
// Relay to nodes at indexes (i+2^k)%n, where
// k: 0..max(1, floor(log2(n-1))-1)
// n: size of the quorum/ring
std::set<uint256> r;
int gap = 1;
int gap_max = (int)mns.size() - 1;
int k = 0;
Expand Down Expand Up @@ -775,8 +778,8 @@ bool EnsureQuorumConnections(const Consensus::LLMQParams& llmqParams, CConnman&
LogPrint(BCLog::NET_NETCONN, "%s -- isMember=%d for quorum %s:\n",
__func__, isMember, pQuorumBaseBlockIndex->GetBlockHash().ToString());

std::set<uint256> connections;
std::set<uint256> relayMembers;
std::unordered_set<uint256, StaticSaltedHasher> connections;
std::unordered_set<uint256, StaticSaltedHasher> relayMembers;
if (isMember) {
connections = GetQuorumConnections(llmqParams, dmnman, sporkman, pQuorumBaseBlockIndex, myProTxHash, true);
relayMembers = GetQuorumRelayMembers(llmqParams, dmnman, pQuorumBaseBlockIndex, myProTxHash, true);
Expand Down
13 changes: 10 additions & 3 deletions src/llmq/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
#ifndef BITCOIN_LLMQ_UTILS_H
#define BITCOIN_LLMQ_UTILS_H

#include <gsl/pointers.h>
#include <llmq/params.h>
#include <saltedhasher.h>
#include <sync.h>
#include <gsl/pointers.h>
#include <uint256.h>

#include <map>
#include <set>
#include <unordered_set>
#include <vector>

class CConnman;
Expand All @@ -34,8 +36,13 @@ namespace utils
std::vector<CDeterministicMNCPtr> GetAllQuorumMembers(Consensus::LLMQType llmqType, CDeterministicMNManager& dmnman, gsl::not_null<const CBlockIndex*> pQuorumBaseBlockIndex, bool reset_cache = false);

uint256 DeterministicOutboundConnection(const uint256& proTxHash1, const uint256& proTxHash2);
std::set<uint256> GetQuorumConnections(const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, const CSporkManager& sporkman, gsl::not_null<const CBlockIndex*> pQuorumBaseBlockIndex, const uint256& forMember, bool onlyOutbound);
std::set<uint256> GetQuorumRelayMembers(const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, gsl::not_null<const CBlockIndex*> pQuorumBaseBlockIndex, const uint256& forMember, bool onlyOutbound);
std::unordered_set<uint256, StaticSaltedHasher> GetQuorumConnections(
const Consensus::LLMQParams& llmqParams, CDeterministicMNManager& dmnman, const CSporkManager& sporkman,
gsl::not_null<const CBlockIndex*> pQuorumBaseBlockIndex, const uint256& forMember, bool onlyOutbound);
std::unordered_set<uint256, StaticSaltedHasher> GetQuorumRelayMembers(const Consensus::LLMQParams& llmqParams,
CDeterministicMNManager& dmnman,
gsl::not_null<const CBlockIndex*> pQuorumBaseBlockIndex,
const uint256& forMember, bool onlyOutbound);
std::set<size_t> CalcDeterministicWatchConnections(Consensus::LLMQType llmqType, gsl::not_null<const CBlockIndex*> pQuorumBaseBlockIndex, size_t memberCount, size_t connectionCount);

bool EnsureQuorumConnections(const Consensus::LLMQParams& llmqParams, CConnman& connman, CDeterministicMNManager& dmnman, const CSporkManager& sporkman,
Expand Down
19 changes: 9 additions & 10 deletions src/net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3718,12 +3718,11 @@ void CConnman::ThreadOpenMasternodeConnections(CDeterministicMNManager& dmnman,

if (!fNetworkActive || !m_masternode_thread_active || !mn_sync.IsBlockchainSynced()) continue;

std::set<CService> connectedNodes;
std::map<uint256 /*proTxHash*/, bool /*fInbound*/> connectedProRegTxHashes;
std::unordered_set<CService, CServiceHash> connectedNodes;
std::unordered_map<uint256 /*proTxHash*/, bool /*fInbound*/, StaticSaltedHasher> connectedProRegTxHashes;
ForEachNode([&](const CNode* pnode) {
auto verifiedProRegTxHash = pnode->GetVerifiedProRegTxHash();
connectedNodes.emplace(pnode->addr);
if (!verifiedProRegTxHash.IsNull()) {
if (auto verifiedProRegTxHash = pnode->GetVerifiedProRegTxHash(); !verifiedProRegTxHash.IsNull()) {
connectedProRegTxHashes.emplace(verifiedProRegTxHash, pnode->IsInboundConn());
}
});
Expand Down Expand Up @@ -4617,7 +4616,7 @@ bool CConnman::AddPendingMasternode(const uint256& proTxHash)
return true;
}

void CConnman::SetMasternodeQuorumNodes(Consensus::LLMQType llmqType, const uint256& quorumHash, const std::set<uint256>& proTxHashes)
void CConnman::SetMasternodeQuorumNodes(Consensus::LLMQType llmqType, const uint256& quorumHash, const std::unordered_set<uint256, StaticSaltedHasher>& proTxHashes)
{
LOCK(cs_vPendingMasternodes);
auto it = masternodeQuorumNodes.emplace(std::make_pair(llmqType, quorumHash), proTxHashes);
Expand All @@ -4626,7 +4625,7 @@ void CConnman::SetMasternodeQuorumNodes(Consensus::LLMQType llmqType, const uint
}
}

void CConnman::SetMasternodeQuorumRelayMembers(Consensus::LLMQType llmqType, const uint256& quorumHash, const std::set<uint256>& proTxHashes)
void CConnman::SetMasternodeQuorumRelayMembers(Consensus::LLMQType llmqType, const uint256& quorumHash, const std::unordered_set<uint256, StaticSaltedHasher>& proTxHashes)
{
{
LOCK(cs_vPendingMasternodes);
Expand Down Expand Up @@ -4657,10 +4656,10 @@ bool CConnman::HasMasternodeQuorumNodes(Consensus::LLMQType llmqType, const uint
return masternodeQuorumNodes.count(std::make_pair(llmqType, quorumHash));
}

std::set<uint256> CConnman::GetMasternodeQuorums(Consensus::LLMQType llmqType) const
std::unordered_set<uint256, StaticSaltedHasher> CConnman::GetMasternodeQuorums(Consensus::LLMQType llmqType) const
{
LOCK(cs_vPendingMasternodes);
std::set<uint256> result;
std::unordered_set<uint256, StaticSaltedHasher> result;
for (const auto& p : masternodeQuorumNodes) {
if (p.first.first != llmqType) {
continue;
Expand All @@ -4670,7 +4669,7 @@ std::set<uint256> CConnman::GetMasternodeQuorums(Consensus::LLMQType llmqType) c
return result;
}

std::set<NodeId> CConnman::GetMasternodeQuorumNodes(Consensus::LLMQType llmqType, const uint256& quorumHash) const
std::unordered_set<NodeId> CConnman::GetMasternodeQuorumNodes(Consensus::LLMQType llmqType, const uint256& quorumHash) const
{
LOCK2(m_nodes_mutex, cs_vPendingMasternodes);
auto it = masternodeQuorumNodes.find(std::make_pair(llmqType, quorumHash));
Expand All @@ -4679,7 +4678,7 @@ std::set<NodeId> CConnman::GetMasternodeQuorumNodes(Consensus::LLMQType llmqType
}
const auto& proRegTxHashes = it->second;

std::set<NodeId> nodes;
std::unordered_set<NodeId> nodes;
for (const auto pnode : m_nodes) {
if (pnode->fDisconnect) {
continue;
Expand Down
12 changes: 6 additions & 6 deletions src/net.h
Original file line number Diff line number Diff line change
Expand Up @@ -1501,12 +1501,12 @@ friend class CNode;
EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex, !mutexMsgProc);

bool AddPendingMasternode(const uint256& proTxHash);
void SetMasternodeQuorumNodes(Consensus::LLMQType llmqType, const uint256& quorumHash, const std::set<uint256>& proTxHashes);
void SetMasternodeQuorumRelayMembers(Consensus::LLMQType llmqType, const uint256& quorumHash, const std::set<uint256>& proTxHashes);
void SetMasternodeQuorumNodes(Consensus::LLMQType llmqType, const uint256& quorumHash, const std::unordered_set<uint256, StaticSaltedHasher>& proTxHashes);
void SetMasternodeQuorumRelayMembers(Consensus::LLMQType llmqType, const uint256& quorumHash, const std::unordered_set<uint256, StaticSaltedHasher>& proTxHashes);
bool HasMasternodeQuorumNodes(Consensus::LLMQType llmqType, const uint256& quorumHash) const;
std::set<uint256> GetMasternodeQuorums(Consensus::LLMQType llmqType) const;
std::unordered_set<uint256, StaticSaltedHasher> GetMasternodeQuorums(Consensus::LLMQType llmqType) const;
// also returns QWATCH nodes
std::set<NodeId> GetMasternodeQuorumNodes(Consensus::LLMQType llmqType, const uint256& quorumHash) const;
std::unordered_set<NodeId> GetMasternodeQuorumNodes(Consensus::LLMQType llmqType, const uint256& quorumHash) const;
void RemoveMasternodeQuorumNodes(Consensus::LLMQType llmqType, const uint256& quorumHash);
bool IsMasternodeQuorumNode(const CNode* pnode, const CDeterministicMNList& tip_mn_list) const;
bool IsMasternodeQuorumRelayMember(const uint256& protxHash);
Expand Down Expand Up @@ -1815,8 +1815,8 @@ friend class CNode;

std::vector<uint256> vPendingMasternodes;
mutable RecursiveMutex cs_vPendingMasternodes;
std::map<std::pair<Consensus::LLMQType, uint256>, std::set<uint256>> masternodeQuorumNodes GUARDED_BY(cs_vPendingMasternodes);
std::map<std::pair<Consensus::LLMQType, uint256>, std::set<uint256>> masternodeQuorumRelayMembers GUARDED_BY(cs_vPendingMasternodes);
std::map<std::pair<Consensus::LLMQType, uint256>, std::unordered_set<uint256, StaticSaltedHasher>> masternodeQuorumNodes GUARDED_BY(cs_vPendingMasternodes);
std::map<std::pair<Consensus::LLMQType, uint256>, std::unordered_set<uint256, StaticSaltedHasher>> masternodeQuorumRelayMembers GUARDED_BY(cs_vPendingMasternodes);
std::set<uint256> masternodePendingProbes GUARDED_BY(cs_vPendingMasternodes);

mutable Mutex cs_mapSocketToNode;
Expand Down

0 comments on commit 941e04e

Please sign in to comment.