From 7148f5e7d755fc2084f53fa22c0761d73c042fbd Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Wed, 19 Apr 2017 18:45:11 +0200 Subject: [PATCH 1/5] Reduce cs_main locks during modal overlay by adding an atomic cache --- src/qt/clientmodel.cpp | 35 +++++++++++++++++++++++++---------- src/qt/clientmodel.h | 8 ++++++-- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index bb10e4942..9a8af01a3 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -36,6 +36,8 @@ ClientModel::ClientModel(OptionsModel *_optionsModel, QObject *parent) : banTableModel(0), pollTimer(0) { + cachedBestHeaderHeight = -1; + cachedBestHeaderTime = -1; peerTableModel = new PeerTableModel(this); banTableModel = new BanTableModel(this); pollTimer = new QTimer(this); @@ -72,20 +74,28 @@ int ClientModel::getNumBlocks() const return chainActive.Height(); } -int ClientModel::getHeaderTipHeight() const +int ClientModel::getHeaderTipHeight() { - LOCK(cs_main); - if (!pindexBestHeader) - return 0; - return pindexBestHeader->nHeight; + if (cachedBestHeaderHeight == -1) { + // make sure we initially populate the cache via a cs_main lock + // otherwise we need to wait for a tip update + LOCK(cs_main); + if (pindexBestHeader) { + cachedBestHeaderHeight = pindexBestHeader->nHeight; + } + } + return cachedBestHeaderHeight; } -int64_t ClientModel::getHeaderTipTime() const +int64_t ClientModel::getHeaderTipTime() { - LOCK(cs_main); - if (!pindexBestHeader) - return 0; - return pindexBestHeader->GetBlockTime(); + if (cachedBestHeaderTime == -1) { + LOCK(cs_main); + if (pindexBestHeader) { + cachedBestHeaderTime = pindexBestHeader->GetBlockTime(); + } + } + return cachedBestHeaderTime; } quint64 ClientModel::getTotalBytesRecv() const @@ -283,6 +293,11 @@ static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CB int64_t& nLastUpdateNotification = fHeader ? nLastHeaderTipUpdateNotification : nLastBlockTipUpdateNotification; + if (fHeader) { + // cache best headers time and height to reduce future cs_main locks + clientmodel->cachedBestHeaderHeight = pIndex->nHeight; + clientmodel->cachedBestHeaderTime = pIndex->GetBlockTime(); + } // if we are in-sync, update the UI regardless of last update time if (!initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) { //pass a async signal to the UI thread diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 2c10e633b..6f7077dad 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -51,8 +51,8 @@ public: //! Return number of connections, default is in- and outbound (total) int getNumConnections(unsigned int flags = CONNECTIONS_ALL) const; int getNumBlocks() const; - int getHeaderTipHeight() const; - int64_t getHeaderTipTime() const; + int getHeaderTipHeight(); + int64_t getHeaderTipTime(); //! Return number of transactions in the mempool long getMempoolSize() const; //! Return the dynamic memory usage of the mempool @@ -81,6 +81,10 @@ public: QString formatClientStartupTime() const; QString dataDir() const; + // caches for the best header + std::atomic cachedBestHeaderHeight; + std::atomic cachedBestHeaderTime; + private: OptionsModel *optionsModel; PeerTableModel *peerTableModel; From cf92bce526d11091b5b39f5d8dbddb972250062f Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Wed, 19 Apr 2017 20:54:30 +0200 Subject: [PATCH 2/5] Update the remaining blocks left in modaloverlay at init. --- src/qt/bitcoingui.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index be79a6799..5c26baef9 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -478,6 +478,7 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel) connect(_clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int))); connect(_clientModel, SIGNAL(networkActiveChanged(bool)), this, SLOT(setNetworkActive(bool))); + modalOverlay->setKnownBestHeight(_clientModel->getHeaderTipHeight(), QDateTime::fromTime_t(_clientModel->getHeaderTipTime())); setNumBlocks(_clientModel->getNumBlocks(), _clientModel->getLastBlockDate(), _clientModel->getVerificationProgress(NULL), false); connect(_clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool))); @@ -505,8 +506,6 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel) // initialize the disable state of the tray icon with the current value in the model. setTrayIconVisible(optionsModel->getHideTrayIcon()); } - - modalOverlay->setKnownBestHeight(clientModel->getHeaderTipHeight(), QDateTime::fromTime_t(clientModel->getHeaderTipTime())); } else { // Disable possibility to show main window via action toggleHideAction->setEnabled(false); From 610a91719c89f9b52f2ae4a5bd039688fe11ffd7 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Thu, 20 Apr 2017 09:51:05 +0200 Subject: [PATCH 3/5] Declare headers height/time cache mutable, re-set the methods const --- src/qt/clientmodel.cpp | 4 ++-- src/qt/clientmodel.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 9a8af01a3..cbc6ca129 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -74,7 +74,7 @@ int ClientModel::getNumBlocks() const return chainActive.Height(); } -int ClientModel::getHeaderTipHeight() +int ClientModel::getHeaderTipHeight() const { if (cachedBestHeaderHeight == -1) { // make sure we initially populate the cache via a cs_main lock @@ -87,7 +87,7 @@ int ClientModel::getHeaderTipHeight() return cachedBestHeaderHeight; } -int64_t ClientModel::getHeaderTipTime() +int64_t ClientModel::getHeaderTipTime() const { if (cachedBestHeaderTime == -1) { LOCK(cs_main); diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 6f7077dad..0e6b34fbf 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -51,8 +51,8 @@ public: //! Return number of connections, default is in- and outbound (total) int getNumConnections(unsigned int flags = CONNECTIONS_ALL) const; int getNumBlocks() const; - int getHeaderTipHeight(); - int64_t getHeaderTipTime(); + int getHeaderTipHeight() const; + int64_t getHeaderTipTime() const; //! Return number of transactions in the mempool long getMempoolSize() const; //! Return the dynamic memory usage of the mempool @@ -82,8 +82,8 @@ public: QString dataDir() const; // caches for the best header - std::atomic cachedBestHeaderHeight; - std::atomic cachedBestHeaderTime; + mutable std::atomic cachedBestHeaderHeight; + mutable std::atomic cachedBestHeaderTime; private: OptionsModel *optionsModel; From 928d4a9ac596db35bf3b8a0c8857cd6e7f87aa2a Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Thu, 20 Apr 2017 09:51:41 +0200 Subject: [PATCH 4/5] Set both time/height header caches at the same time --- src/qt/clientmodel.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index cbc6ca129..20d468797 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -82,6 +82,7 @@ int ClientModel::getHeaderTipHeight() const LOCK(cs_main); if (pindexBestHeader) { cachedBestHeaderHeight = pindexBestHeader->nHeight; + cachedBestHeaderTime = pindexBestHeader->GetBlockTime(); } } return cachedBestHeaderHeight; @@ -92,6 +93,7 @@ int64_t ClientModel::getHeaderTipTime() const if (cachedBestHeaderTime == -1) { LOCK(cs_main); if (pindexBestHeader) { + cachedBestHeaderHeight = pindexBestHeader->nHeight; cachedBestHeaderTime = pindexBestHeader->GetBlockTime(); } } From 4082fb0003ca1992c34e9f4c75fba9db281f5fc0 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Thu, 20 Apr 2017 13:29:12 +0200 Subject: [PATCH 5/5] Add missing header in clientmodel.h --- src/qt/clientmodel.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 0e6b34fbf..4c92e2144 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -8,6 +8,8 @@ #include #include +#include + class AddressTableModel; class BanTableModel; class OptionsModel;