From a1c84c7172fab017a82fa93f93e54fc7cb972661 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 4 May 2015 16:23:02 +0200 Subject: [PATCH] blockchain download and import performance optimizations --- alethzero/DownloadView.cpp | 4 ++-- libdevcore/Guards.h | 13 +++++++++++++ libdevcore/Log.cpp | 4 ++-- libethcore/EthashAux.cpp | 11 +++++------ libethereum/BlockChain.cpp | 10 +++++++--- libethereum/BlockChain.h | 1 - libethereum/DownloadMan.cpp | 2 +- libethereum/DownloadMan.h | 3 ++- libethereum/EthereumHost.cpp | 2 +- libethereum/EthereumPeer.cpp | 19 +++++++++++-------- 10 files changed, 44 insertions(+), 25 deletions(-) diff --git a/alethzero/DownloadView.cpp b/alethzero/DownloadView.cpp index 88a595566..009e2dc83 100644 --- a/alethzero/DownloadView.cpp +++ b/alethzero/DownloadView.cpp @@ -39,13 +39,13 @@ void DownloadView::paintEvent(QPaintEvent*) QPainter p(this); p.fillRect(rect(), Qt::white); - if (!m_man || m_man->chain().empty() || !m_man->subCount()) + if (!m_man || m_man->chainEmpty() || !m_man->subCount()) return; double ratio = (double)rect().width() / rect().height(); if (ratio < 1) ratio = 1 / ratio; - double n = min(16.0, min(rect().width(), rect().height()) / ceil(sqrt(m_man->chain().size() / ratio))); + double n = min(16.0, min(rect().width(), rect().height()) / ceil(sqrt(m_man->chainSize() / ratio))); // QSizeF area(rect().width() / floor(rect().width() / n), rect().height() / floor(rect().height() / n)); QSizeF area(n, n); diff --git a/libdevcore/Guards.h b/libdevcore/Guards.h index 4229428ce..8d2e8961d 100644 --- a/libdevcore/Guards.h +++ b/libdevcore/Guards.h @@ -22,6 +22,7 @@ #pragma once #include +#include #include namespace dev @@ -61,6 +62,18 @@ struct GenericUnguardSharedBool MutexType& m; }; +/** @brief Simple lock that waits for release without making context switch */ +class SpinLock +{ +public: + SpinLock() { lck.clear(); } + void lock() { while (lck.test_and_set(std::memory_order_acquire)) {} } + void unlock() { lck.clear(std::memory_order_release); } +private: + std::atomic_flag lck; +}; +using SpinGuard = std::lock_guard; + /** @brief Simple block guard. * The expression/block following is guarded though the given mutex. * Usage: diff --git a/libdevcore/Log.cpp b/libdevcore/Log.cpp index e086278ec..3dd2b3879 100644 --- a/libdevcore/Log.cpp +++ b/libdevcore/Log.cpp @@ -158,8 +158,8 @@ void dev::setThreadName(string const& _n) void dev::simpleDebugOut(std::string const& _s, char const*) { - static Mutex s_lock; - Guard l(s_lock); + static SpinLock s_lock; + SpinGuard l(s_lock); cerr << _s << endl << flush; diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 9cb4d9fad..dd7e92a66 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -87,13 +87,10 @@ ethash_params EthashAux::params(h256 const& _seedHash) { Guard l(get()->x_epochs); unsigned epoch = 0; - try + auto epochIter = get()->m_epochs.find(_seedHash); + if (epochIter == get()->m_epochs.end()) { - epoch = get()->m_epochs.at(_seedHash); - } - catch (...) - { -// cdebug << "Searching for seedHash " << _seedHash; + // cdebug << "Searching for seedHash " << _seedHash; for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = sha3(h), get()->m_epochs[h] = epoch) {} if (epoch == 2048) { @@ -102,6 +99,8 @@ ethash_params EthashAux::params(h256 const& _seedHash) throw std::invalid_argument(error.str()); } } + else + epoch = epochIter->second; return params(epoch * ETHASH_EPOCH_LENGTH); } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 69078b400..49e73f1bf 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -293,9 +293,14 @@ LastHashes BlockChain::lastHashes(unsigned _n) const Guard l(x_lastLastHashes); if (m_lastLastHashesNumber != _n || m_lastLastHashes.empty()) { - m_lastLastHashes.resize(256); + LastHashes lastHashes(256); + //m_lastLastHashes.resize(256); for (unsigned i = 0; i < 256; ++i) - m_lastLastHashes[i] = _n >= i ? numberHash(_n - i) : h256(); + { + size_t prevIndex = m_lastLastHashesNumber - _n + i; + lastHashes[i] = (prevIndex >= 0 && prevIndex < m_lastLastHashes.size()) ? m_lastLastHashes[prevIndex] : (_n >= i ? numberHash(_n - i) : h256()); + } + m_lastLastHashes = std::move(lastHashes); m_lastLastHashesNumber = _n; } return m_lastLastHashes; @@ -609,7 +614,6 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import } clog(BlockChainNote) << " Imported and best" << td << " (#" << bi.number << "). Has" << (details(bi.parentHash).children.size() - 1) << "siblings. Route:" << route; - noteCanonChanged(); StructuredLogger::chainNewHead( bi.headerHash(WithoutNonce).abridged(), diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index d04bff298..5756d1811 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -300,7 +300,6 @@ private: void noteUsed(h256 const& _h, unsigned _extra = (unsigned)-1) const; std::chrono::system_clock::time_point m_lastCollection; - void noteCanonChanged() const { Guard l(x_lastLastHashes); m_lastLastHashes.clear(); } mutable Mutex x_lastLastHashes; mutable LastHashes m_lastLastHashes; mutable unsigned m_lastLastHashesNumber = (unsigned)-1; diff --git a/libethereum/DownloadMan.cpp b/libethereum/DownloadMan.cpp index be33f5187..1b73dca5b 100644 --- a/libethereum/DownloadMan.cpp +++ b/libethereum/DownloadMan.cpp @@ -50,7 +50,7 @@ h256Set DownloadSub::nextFetch(unsigned _n) m_indices.clear(); m_remaining.clear(); - if (!m_man || m_man->chain().empty()) + if (!m_man || m_man->chainEmpty()) return h256Set(); m_asked = (~(m_man->taken() + m_attempted)).lowest(_n); diff --git a/libethereum/DownloadMan.h b/libethereum/DownloadMan.h index d32d0465c..82e0f09e2 100644 --- a/libethereum/DownloadMan.h +++ b/libethereum/DownloadMan.h @@ -143,7 +143,8 @@ public: return ret; } - h256s chain() const { ReadGuard l(m_lock); return m_chain; } + size_t chainSize() const { ReadGuard l(m_lock); return m_chain.size(); } + size_t chainEmpty() const { ReadGuard l(m_lock); return m_chain.empty(); } void foreachSub(std::function const& _f) const { ReadGuard l(x_subs); for(auto i: m_subs) _f(*i); } unsigned subCount() const { ReadGuard l(x_subs); return m_subs.size(); } RangeMask blocksGot() const { ReadGuard l(m_lock); return m_blocksGot; } diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index c98dd7642..340ae417f 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -122,7 +122,7 @@ void EthereumHost::noteDoneBlocks(EthereumPeer* _who, bool _clemency) // Done our chain-get. clog(NetNote) << "Chain download complete."; // 1/100th for each useful block hash. - _who->addRating(m_man.chain().size() / 100); + _who->addRating(m_man.chainSize() / 100); m_man.reset(); } else if (_who->isSyncing()) diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index f3edaf8ea..249831540 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -329,9 +329,10 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) case GetTransactionsPacket: break; // DEPRECATED. case TransactionsPacket: { - clog(NetAllDetail) << "Transactions (" << dec << _r.itemCount() << "entries)"; + unsigned itemCount = _r.itemCount(); + clog(NetAllDetail) << "Transactions (" << dec << itemCount << "entries)"; Guard l(x_knownTransactions); - for (unsigned i = 0; i < _r.itemCount(); ++i) + for (unsigned i = 0; i < itemCount; ++i) { auto h = sha3(_r[i].data()); m_knownTransactions.insert(h); @@ -373,21 +374,22 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) } case BlockHashesPacket: { - clog(NetMessageSummary) << "BlockHashes (" << dec << _r.itemCount() << "entries)" << (_r.itemCount() ? "" : ": NoMoreHashes"); + unsigned itemCount = _r.itemCount(); + clog(NetMessageSummary) << "BlockHashes (" << dec << itemCount << "entries)" << (itemCount ? "" : ": NoMoreHashes"); if (m_asking != Asking::Hashes) { cwarn << "Peer giving us hashes when we didn't ask for them."; break; } - if (_r.itemCount() == 0) + if (itemCount == 0) { transition(Asking::Blocks); return true; } unsigned knowns = 0; unsigned unknowns = 0; - for (unsigned i = 0; i < _r.itemCount(); ++i) + for (unsigned i = 0; i < itemCount; ++i) { addRating(1); auto h = _r[i].toHash(); @@ -454,12 +456,13 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) } case BlocksPacket: { - clog(NetMessageSummary) << "Blocks (" << dec << _r.itemCount() << "entries)" << (_r.itemCount() ? "" : ": NoMoreBlocks"); + unsigned itemCount = _r.itemCount(); + clog(NetMessageSummary) << "Blocks (" << dec << itemCount << "entries)" << (itemCount ? "" : ": NoMoreBlocks"); if (m_asking != Asking::Blocks) clog(NetWarn) << "Unexpected Blocks received!"; - if (_r.itemCount() == 0) + if (itemCount == 0) { // Got to this peer's latest block - just give up. transition(Asking::Nothing); @@ -472,7 +475,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) unsigned got = 0; unsigned repeated = 0; - for (unsigned i = 0; i < _r.itemCount(); ++i) + for (unsigned i = 0; i < itemCount; ++i) { auto h = BlockInfo::headerHash(_r[i].data()); if (m_sub.noteBlock(h))