From da1357e6cce51c9ed3cd1c1f0c8e5593fd5b3a22 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 1 Jul 2015 17:38:15 +0200 Subject: [PATCH 1/3] Use real number of cores for default -par, ignore virtual cores To determine the default for `-par`, the number of script verification threads, use [boost::thread::physical_concurrency()](http://www.boost.org/doc/libs/1_58_0/doc/html/thread/thread_management.html#thread.thread_management.thread.physical_concurrency) which counts only physical cores, not virtual cores. Virtual cores are roughly a set of cached registers to avoid context switches while threading, they cannot actually perform work, so spawning a verification thread for them could even reduce efficiency and will put undue load on the system. Should fix issue #6358, as well as some other reported system overload issues, especially on Intel processors. The function was only introduced in boost 1.56, so provide a utility function `GetNumCores` to fall back for older Boost versions. --- src/init.cpp | 4 ++-- src/miner.cpp | 2 +- src/util.cpp | 10 ++++++++++ src/util.h | 7 +++++++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index ec3553c4..5e133de9 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -333,7 +333,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-loadblock=", _("Imports blocks from external blk000??.dat file") + " " + _("on startup")); strUsage += HelpMessageOpt("-maxorphantx=", strprintf(_("Keep at most unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS)); strUsage += HelpMessageOpt("-par=", strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"), - -(int)boost::thread::hardware_concurrency(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS)); + -GetNumCores(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS)); #ifndef WIN32 strUsage += HelpMessageOpt("-pid=", strprintf(_("Specify pid file (default: %s)"), "zcashd.pid")); #endif @@ -901,7 +901,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency nScriptCheckThreads = GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS); if (nScriptCheckThreads <= 0) - nScriptCheckThreads += boost::thread::hardware_concurrency(); + nScriptCheckThreads += GetNumCores(); if (nScriptCheckThreads <= 1) nScriptCheckThreads = 0; else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS) diff --git a/src/miner.cpp b/src/miner.cpp index e65b9c5f..32026209 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -753,7 +753,7 @@ void GenerateBitcoins(bool fGenerate, int nThreads) if (Params().DefaultMinerThreads()) nThreads = Params().DefaultMinerThreads(); else - nThreads = boost::thread::hardware_concurrency(); + nThreads = GetNumCores(); } if (minerThreads != NULL) diff --git a/src/util.cpp b/src/util.cpp index 420ce043..233ec322 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -908,3 +908,13 @@ std::string LicenseInfo() FormatParagraph(_("This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.")) + "\n"; } + +int GetNumCores() +{ +#if BOOST_VERSION >= 105600 + return boost::thread::physical_concurrency(); +#else // Must fall back to hardware_concurrency, which unfortunately counts virtual cores + return boost::thread::hardware_concurrency(); +#endif +} + diff --git a/src/util.h b/src/util.h index 00c48582..392ddff9 100644 --- a/src/util.h +++ b/src/util.h @@ -219,6 +219,13 @@ std::string HelpMessageGroup(const std::string& message); */ std::string HelpMessageOpt(const std::string& option, const std::string& message); +/** + * Return the number of physical cores available on the current system. + * @note This does not count virtual cores, such as those provided by HyperThreading + * when boost is newer than 1.56. + */ +int GetNumCores(); + void SetThreadPriority(int nPriority); void RenameThread(const char* name); From 2854c4e366d2aa4f7377d037ef94c02d59cff31d Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 3 Jul 2015 09:13:56 +0200 Subject: [PATCH 2/3] Remove ChainParams::DefaultMinerThreads No longer relevant after #5957. This hack existed because of another hack where the numthreads parameter, on regtest, doubled as how many blocks to generate. --- src/chainparams.cpp | 3 --- src/chainparams.h | 3 --- src/miner.cpp | 9 ++------- 3 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index ce71a3aa..3a1691ee 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -59,7 +59,6 @@ public: pchMessageStart[3] = 0x64; vAlertPubKey = ParseHex("04b7ecf0baa90495ceb4e4090f6b2fd37eec1e9c85fac68a487f3ce11589692e4a317479316ee814e066638e1db54e37a10689b70286e6315b1087b6615d179264"); nDefaultPort = 8233; - nMinerThreads = 0; nMaxTipAge = 24 * 60 * 60; nPruneAfterHeight = 100000; const size_t N = 200, K = 9; @@ -219,7 +218,6 @@ public: pchMessageStart[3] = 0xbf; vAlertPubKey = ParseHex("044e7a1553392325c871c5ace5d6ad73501c66f4c185d6b0453cf45dec5a1322e705c672ac1a27ef7cdaf588c10effdf50ed5f95f85f2f54a5f6159fca394ed0c6"); nDefaultPort = 18233; - nMinerThreads = 0; nPruneAfterHeight = 1000; //! Modify the testnet genesis block so the timestamp is valid for a later start. @@ -308,7 +306,6 @@ public: pchMessageStart[1] = 0xe8; pchMessageStart[2] = 0x3f; pchMessageStart[3] = 0x5f; - nMinerThreads = 1; nMaxTipAge = 24 * 60 * 60; const size_t N = 48, K = 5; BOOST_STATIC_ASSERT(equihash_parameters_acceptable(N, K)); diff --git a/src/chainparams.h b/src/chainparams.h index dc7cbc38..a1de7b49 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -53,8 +53,6 @@ public: const std::vector& AlertKey() const { return vAlertPubKey; } int GetDefaultPort() const { return nDefaultPort; } - /** Used if GenerateBitcoins is called with a negative number of threads */ - int DefaultMinerThreads() const { return nMinerThreads; } const CBlock& GenesisBlock() const { return genesis; } /** Make miner wait to have peers to avoid wasting work */ bool MiningRequiresPeers() const { return fMiningRequiresPeers; } @@ -91,7 +89,6 @@ protected: //! Raw pub key bytes for the broadcast alert signing key. std::vector vAlertPubKey; int nDefaultPort = 0; - int nMinerThreads = 0; long nMaxTipAge = 0; uint64_t nPruneAfterHeight = 0; unsigned int nEquihashN = 0; diff --git a/src/miner.cpp b/src/miner.cpp index 32026209..3434a0d7 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -748,13 +748,8 @@ void GenerateBitcoins(bool fGenerate, int nThreads) { static boost::thread_group* minerThreads = NULL; - if (nThreads < 0) { - // In regtest threads defaults to 1 - if (Params().DefaultMinerThreads()) - nThreads = Params().DefaultMinerThreads(); - else - nThreads = GetNumCores(); - } + if (nThreads < 0) + nThreads = GetNumCores(); if (minerThreads != NULL) { From 0d0265fd11b8acbbebbbb8d1f6e9668c4ff3c41d Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 14 Feb 2017 22:06:35 +0000 Subject: [PATCH 3/3] Use AtomicTimer for metrics screen thread count --- src/metrics.cpp | 17 ++++++++--------- src/metrics.h | 2 ++ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/metrics.cpp b/src/metrics.cpp index fd800054..db0d1965 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -45,6 +45,12 @@ bool AtomicTimer::running() return threads > 0; } +uint64_t AtomicTimer::threadCount() +{ + std::unique_lock lock(mtx); + return threads; +} + double AtomicTimer::rate(const AtomicCounter& count) { std::unique_lock lock(mtx); @@ -191,15 +197,8 @@ int printMiningStatus(bool mining) int lines = 1; if (mining) { - int nThreads = GetArg("-genproclimit", 1); - if (nThreads < 0) { - // In regtest threads defaults to 1 - if (Params().DefaultMinerThreads()) - nThreads = Params().DefaultMinerThreads(); - else - nThreads = boost::thread::hardware_concurrency(); - } - if (miningTimer.running()) { + auto nThreads = miningTimer.threadCount(); + if (nThreads > 0) { std::cout << strprintf(_("You are mining with the %s solver on %d threads."), GetArg("-equihashsolver", "default"), nThreads) << std::endl; } else { diff --git a/src/metrics.h b/src/metrics.h index 3e830f82..701306a4 100644 --- a/src/metrics.h +++ b/src/metrics.h @@ -49,6 +49,8 @@ public: bool running(); + uint64_t threadCount(); + double rate(const AtomicCounter& count); };