Skip to content

Commit 756fc4f

Browse files
committed
perf: warm quorum public key shares on the BLS worker pool
CQuorumManager ran a dedicated thread that polled a queue every 100 ms only to precompute the public key shares of freshly built quorums. That is BLS work with no ordering or latency requirement of its own, so push each quorum as a job to the CBLSWorker pool instead. One thread less per node (0.9 MB of thread-local storage each while the BLS library keeps its context per thread), no idle polling, and the queue, its mutex and the interrupt go away with it. A job only holds a shared_ptr to its quorum, so it needs nothing from the manager and Stop() of the pool drains it on shutdown.
1 parent a739cf7 commit 756fc4f

5 files changed

Lines changed: 33 additions & 60 deletions

File tree

‎src/bls/bls_worker.cpp‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ void CBLSWorker::Stop()
6969
workerPool.stop(true);
7070
}
7171

72+
void CBLSWorker::PushJob(std::function<void()> job)
73+
{
74+
workerPool.push([job = std::move(job)](int) { job(); });
75+
}
76+
7277
#ifndef BUILD_BITCOIN_INTERNAL
7378
bool CBLSWorker::GenerateContributions(int quorumThreshold, Span<CBLSId> ids, BLSVerificationVectorPtr& vvecRet, std::vector<CBLSSecretKey>& skSharesRet)
7479
{

‎src/bls/bls_worker.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class CBLSWorker
5656

5757
void Start(int16_t worker_count);
5858
void Stop();
59+
void PushJob(std::function<void()> job);
5960

6061
#ifndef BUILD_BITCOIN_INTERNAL
6162
bool GenerateContributions(int threshold, Span<CBLSId> ids, BLSVerificationVectorPtr& vvecRet, std::vector<CBLSSecretKey>& skSharesRet);

‎src/llmq/context.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,6 @@ LLMQContext::LLMQContext(CDeterministicMNManager& dmnman, CEvoDB& evo_db, Chains
2828

2929
LLMQContext::~LLMQContext()
3030
{
31+
qman->InterruptWarming();
3132
bls_worker->Stop();
3233
}

‎src/llmq/quorumsman.cpp‎

Lines changed: 12 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
#include <chainparams.h>
2323
#include <dbwrapper.h>
2424
#include <logging.h>
25-
#include <util/thread.h>
2625
#include <util/time.h>
2726
#include <validation.h>
2827

@@ -40,18 +39,10 @@ CQuorumManager::CQuorumManager(CBLSWorker& _blsWorker, CDeterministicMNManager&
4039
db{util::MakeDbWrapper({db_params.path / "llmq" / "quorumdb", db_params.memory, db_params.wipe, /*cache_size=*/1 << 20})}
4140
{
4241
mapQuorumsCache.Init(m_chainman.GetConsensus(), /*limit_by_connections=*/false);
43-
m_cache_interrupt.reset();
44-
m_cache_thread = std::thread(&util::TraceThread, "q-cache", [this] { CacheWarmingThreadMain(); });
4542
MigrateOldQuorumDB(_evoDb);
4643
}
4744

48-
CQuorumManager::~CQuorumManager()
49-
{
50-
if (m_cache_thread.joinable()) {
51-
m_cache_interrupt();
52-
m_cache_thread.join();
53-
}
54-
}
45+
CQuorumManager::~CQuorumManager() = default;
5546

5647
bool CQuorumManager::GetEncryptedContributions(Consensus::LLMQType llmq_type, const CBlockIndex* block_index,
5748
const std::vector<bool>& valid_members, const uint256& protx_hash,
@@ -505,50 +496,29 @@ void CQuorumManager::WriteContributions(const CQuorumPtr& quorum) const
505496
quorum->WriteContributions(*db);
506497
}
507498

508-
void CQuorumManager::CacheWarmingThreadMain() const
499+
void CQuorumManager::QueueQuorumForWarming(CQuorumCPtr pQuorum) const
509500
{
510-
while (!m_cache_interrupt) {
511-
CQuorumCPtr pQuorum;
512-
{
513-
LOCK(m_cache_cs);
514-
if (!m_cache_queue.empty()) {
515-
pQuorum = std::move(m_cache_queue.front());
516-
m_cache_queue.pop_front();
517-
};
518-
}
519-
520-
if (!pQuorum) {
521-
m_cache_interrupt.sleep_for(std::chrono::milliseconds(100));
522-
continue;
523-
}
524-
501+
if (!pQuorum->HasVerificationVector()) {
502+
return;
503+
}
504+
// The job may reference this manager: ~LLMQContext stops the worker pool before destroying it.
505+
blsWorker.PushJob([this, pQuorum = std::move(pQuorum)]() {
525506
cxxtimer::Timer t(true);
526-
LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- type=%d height=%d hash=%s start\n", __func__,
507+
LogPrint(BCLog::LLMQ, "CQuorumManager::QueueQuorumForWarming -- type=%d height=%d hash=%s start\n",
527508
std23::to_underlying(pQuorum->params.type), pQuorum->m_quorum_base_block_index->nHeight,
528509
pQuorum->m_quorum_base_block_index->GetBlockHash().ToString());
529-
530-
// when then later some other thread tries to get keys, it will be much faster
531510
for (const auto i : util::irange(pQuorum->members.size())) {
532-
if (m_cache_interrupt) {
533-
break;
511+
if (m_warming_interrupted) {
512+
return;
534513
}
535514
if (pQuorum->qc->validMembers[i]) {
536515
pQuorum->GetPubKeyShare(i);
537516
}
538517
}
539-
540-
LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- type=%d height=%d hash=%s done. time=%d\n", __func__,
518+
LogPrint(BCLog::LLMQ, "CQuorumManager::QueueQuorumForWarming -- type=%d height=%d hash=%s done. time=%d\n",
541519
std23::to_underlying(pQuorum->params.type), pQuorum->m_quorum_base_block_index->nHeight,
542520
pQuorum->m_quorum_base_block_index->GetBlockHash().ToString(), t.count());
543-
}
544-
}
545-
546-
void CQuorumManager::QueueQuorumForWarming(CQuorumCPtr pQuorum) const
547-
{
548-
if (pQuorum->HasVerificationVector()) {
549-
LOCK(m_cache_cs);
550-
m_cache_queue.push_back(std::move(pQuorum));
551-
}
521+
});
552522
}
553523

554524
// TODO: remove in v23

‎src/llmq/quorumsman.h‎

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,12 @@
1515
#include <unordered_lru_cache.h>
1616

1717
#include <sync.h>
18-
#include <util/threadinterrupt.h>
1918

2019
#include <gsl/pointers.h>
2120

22-
#include <deque>
21+
#include <atomic>
2322
#include <map>
2423
#include <memory>
25-
#include <thread>
2624

2725
class CBLSSignature;
2826
class CBLSWorker;
@@ -96,10 +94,7 @@ class CQuorumManager final
9694
mutable Uint256LruHashMap<const CBlockIndex*, /*max_size=*/128> quorumBaseBlockIndexCache
9795
GUARDED_BY(cs_quorumBaseBlockIndexCache);
9896

99-
mutable Mutex m_cache_cs;
100-
mutable std::deque<CQuorumCPtr> m_cache_queue GUARDED_BY(m_cache_cs);
101-
mutable CThreadInterrupt m_cache_interrupt;
102-
mutable std::thread m_cache_thread;
97+
std::atomic<bool> m_warming_interrupted{false};
10398

10499
public:
105100
CQuorumManager() = delete;
@@ -135,20 +130,20 @@ class CQuorumManager final
135130

136131
// all these methods will lock cs_main for a short period of time
137132
CQuorumCPtr GetQuorum(Consensus::LLMQType llmqType, const uint256& quorumHash) const
138-
EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !m_cs_maps, !m_cache_cs);
133+
EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !m_cs_maps);
139134
CQuorumCPtr GetQuorum(Consensus::LLMQType llmqType, const uint256& quorumHash, const CChain& chain) const
140-
EXCLUSIVE_LOCKS_REQUIRED(::cs_main, !cs_db, !m_cs_maps, !m_cache_cs);
135+
EXCLUSIVE_LOCKS_REQUIRED(::cs_main, !cs_db, !m_cs_maps);
141136
std::vector<CQuorumCPtr> ScanQuorums(Consensus::LLMQType llmqType, size_t nCountRequested) const
142-
EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !m_cs_maps, !m_cache_cs);
137+
EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !m_cs_maps);
143138

144139
// this one is cs_main-free
145140
std::vector<CQuorumCPtr> ScanQuorums(Consensus::LLMQType llmqType, gsl::not_null<const CBlockIndex*> pindexStart,
146141
size_t nCountRequested) const
147-
EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !m_cs_maps, !m_cache_cs);
142+
EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !m_cs_maps);
148143
std::vector<CQuorumCPtr> ScanQuorums(Consensus::LLMQType llmqType,
149144
gsl::not_null<const CBlockIndex*> pindexStart,
150145
size_t nCountRequested, const CChain& chain) const
151-
EXCLUSIVE_LOCKS_REQUIRED(::cs_main, !cs_db, !m_cs_maps, !m_cache_cs);
146+
EXCLUSIVE_LOCKS_REQUIRED(::cs_main, !cs_db, !m_cs_maps);
152147

153148
bool IsMasternode() const;
154149
bool IsWatching() const;
@@ -175,29 +170,30 @@ class CQuorumManager final
175170
CQuorumPtr GetCachedMutableQuorum(Consensus::LLMQType llmqType, const uint256& quorumHash) const
176171
EXCLUSIVE_LOCKS_REQUIRED(!m_cs_maps);
177172
void WriteContributions(const CQuorumPtr& quorum) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db);
178-
void QueueQuorumForWarming(CQuorumCPtr pQuorum) const EXCLUSIVE_LOCKS_REQUIRED(!m_cache_cs);
173+
void QueueQuorumForWarming(CQuorumCPtr pQuorum) const;
174+
/** Make queued and running warming jobs return; call before stopping the BLS worker pool */
175+
void InterruptWarming() { m_warming_interrupted = true; }
179176

180177
private:
181178
// all private methods here are cs_main-free
182179
std::vector<CQuorumCPtr> ScanQuorums(Consensus::LLMQType llmqType,
183180
gsl::not_null<const CBlockIndex*> pindexStart,
184181
size_t nCountRequested, const CChain* chain) const
185-
EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !m_cs_maps, !m_cache_cs);
182+
EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !m_cs_maps);
186183
bool BuildQuorumContributions(const CFinalCommitmentPtr& fqc, const std::shared_ptr<CQuorum>& quorum) const;
187184

188185
CQuorumPtr BuildQuorumFromCommitment(Consensus::LLMQType llmqType,
189186
gsl::not_null<const CBlockIndex*> pQuorumBaseBlockIndex,
190187
bool populate_cache) const
191-
EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !m_cs_maps, !m_cache_cs);
188+
EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !m_cs_maps);
192189

193190
CQuorumCPtr GetQuorum(Consensus::LLMQType llmqType, gsl::not_null<const CBlockIndex*> pindex,
194191
bool populate_cache = true) const
195-
EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !m_cs_maps, !m_cache_cs);
192+
EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !m_cs_maps);
196193
CQuorumCPtr GetQuorum(Consensus::LLMQType llmqType, gsl::not_null<const CBlockIndex*> pindex,
197194
const CChain& chain, bool populate_cache = true) const
198-
EXCLUSIVE_LOCKS_REQUIRED(::cs_main, !cs_db, !m_cs_maps, !m_cache_cs);
195+
EXCLUSIVE_LOCKS_REQUIRED(::cs_main, !cs_db, !m_cs_maps);
199196

200-
void CacheWarmingThreadMain() const EXCLUSIVE_LOCKS_REQUIRED(!m_cache_cs);
201197
void MigrateOldQuorumDB(CEvoDB& evoDb) const EXCLUSIVE_LOCKS_REQUIRED(!cs_db);
202198
};
203199

0 commit comments

Comments
 (0)