From a6df7ab5679608a0ee0daa7dce33dd61bc4b3584 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sun, 4 Sep 2016 04:39:45 +1200 Subject: [PATCH 01/12] Add a persistent screen showing basic node metrics The screen is implemented using ANSI Escape sequences. Closes #1331 --- src/Makefile.am | 2 + src/init.cpp | 6 +++ src/main.cpp | 6 +++ src/metrics.cpp | 104 ++++++++++++++++++++++++++++++++++++++++++++++ src/metrics.h | 68 ++++++++++++++++++++++++++++++ src/miner.cpp | 14 ++++++- src/rpcmining.cpp | 7 +++- 7 files changed, 204 insertions(+), 3 deletions(-) create mode 100644 src/metrics.cpp create mode 100644 src/metrics.h diff --git a/src/Makefile.am b/src/Makefile.am index 7467919d4d6..8ded268cfde 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -120,6 +120,7 @@ BITCOIN_CORE_H = \ main.h \ memusage.h \ merkleblock.h \ + metrics.h \ miner.h \ mruset.h \ net.h \ @@ -205,6 +206,7 @@ libbitcoin_server_a_SOURCES = \ leveldbwrapper.cpp \ main.cpp \ merkleblock.cpp \ + metrics.cpp \ miner.cpp \ net.cpp \ noui.cpp \ diff --git a/src/init.cpp b/src/init.cpp index 37564d951b5..a24a1782287 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -16,6 +16,7 @@ #include "consensus/validation.h" #include "key.h" #include "main.h" +#include "metrics.h" #include "miner.h" #include "net.h" #include "rpcserver.h" @@ -975,6 +976,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) CScheduler::Function serviceLoop = boost::bind(&CScheduler::serviceQueue, &scheduler); threadGroup.create_thread(boost::bind(&TraceThread, "scheduler", serviceLoop)); + if (GetBoolArg("-showmetrics", true) && !fPrintToConsole && !GetBoolArg("-daemon", false)) { + // Start the persistent metrics interface + threadGroup.create_thread(&ThreadShowMetricsScreen); + } + // Initialize Zcash circuit parameters ZC_LoadParams(); // These must be disabled for now, they are buggy and we probably don't diff --git a/src/main.cpp b/src/main.cpp index 699b28b5a88..ca8f0f8d716 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,6 +16,7 @@ #include "consensus/validation.h" #include "init.h" #include "merkleblock.h" +#include "metrics.h" #include "net.h" #include "pow.h" #include "txdb.h" @@ -833,6 +834,11 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in bool CheckTransaction(const CTransaction& tx, CValidationState &state) { + // Don't count coinbase transactions because mining skews the count + if (!tx.IsCoinBase()) { + transactionsValidated.increment(); + } + if (!CheckTransactionWithoutProofVerification(tx, state)) { return false; } else { diff --git a/src/metrics.cpp b/src/metrics.cpp new file mode 100644 index 00000000000..ad58ab41f11 --- /dev/null +++ b/src/metrics.cpp @@ -0,0 +1,104 @@ +// Copyright (c) 2016 The Zcash developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "metrics.h" + +#include "chainparams.h" +#include "util.h" +#include "utiltime.h" + +#include + +AtomicCounter transactionsValidated; +AtomicCounter ehSolverRuns; +AtomicCounter minedBlocks; + +void ThreadShowMetricsScreen() +{ + // Make this thread recognisable as the metrics screen thread + RenameThread("zcash-metrics-screen"); + + // Clear screen + std::cout << "\e[2J"; + + // Print art + std::cout << METRICS_ART << std::endl; + std::cout << std::endl; + + // Thank you text + std::cout << OFFSET << "Thank you for running a Zcash node!" << std::endl; + std::cout << OFFSET << "By running this node, you're contributing to the social good :)" << std::endl; + std::cout << std::endl; + + // Miner status + bool mining = GetBoolArg("-gen", false); + 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(); + } + std::cout << OFFSET << "You are running " << nThreads << " mining threads." << std::endl; + } else { + std::cout << OFFSET << "You are currently not mining." << std::endl; + std::cout << OFFSET << "To enable mining, add 'gen=1' to your zcash.conf and restart." << std::endl; + } + std::cout << std::endl; + + // Count uptime + int64_t nStart = GetTime(); + + while (true) { + int lines = 4; + + // Erase below current position + std::cout << "\e[J"; + + // Calculate uptime + int64_t uptime = GetTime() - nStart; + int days = uptime / (24 * 60 * 60); + int hours = (uptime - (days * 24 * 60 * 60)) / (60 * 60); + int minutes = (uptime - (((days * 24) + hours) * 60 * 60)) / 60; + int seconds = uptime - (((((days * 24) + hours) * 60) + minutes) * 60); + + // Display uptime + std::cout << OFFSET << "Since starting this node "; + if (days > 0) { + std::cout << days << " days, "; + } + if (hours > 0) { + std::cout << hours << " hours, "; + } + if (minutes > 0) { + std::cout << minutes << " minutes, "; + } + std::cout << seconds << " seconds ago:" << std::endl; + + std::cout << OFFSET << "- You have validated " << transactionsValidated.get() << " transactions." << std::endl; + + if (mining) { + std::cout << OFFSET << "- You have completed " << ehSolverRuns.get() << " Equihash solver runs." << std::endl; + lines++; + + int mined = minedBlocks.get(); + if (mined > 0) { + std::cout << OFFSET << "- You have mined " << mined << " blocks!" << std::endl; + lines++; + } + } + + // Explain how to exit + std::cout << std::endl; + std::cout << "[Hit Ctrl+C to exit] [Set 'showmetrics=0' to hide]" << std::endl;; + + boost::this_thread::interruption_point(); + MilliSleep(1000); + + // Return to the top of the updating section + std::cout << "\e[" << lines << "A"; + } +} diff --git a/src/metrics.h b/src/metrics.h new file mode 100644 index 00000000000..f1fa13d58f0 --- /dev/null +++ b/src/metrics.h @@ -0,0 +1,68 @@ +// Copyright (c) 2016 The Zcash developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include + +struct AtomicCounter { + std::atomic value; + + AtomicCounter() : value {0} { } + + void increment(){ + ++value; + } + + void decrement(){ + --value; + } + + int get(){ + return value.load(); + } +}; + +extern AtomicCounter transactionsValidated; +extern AtomicCounter ehSolverRuns; +extern AtomicCounter minedBlocks; + +void ThreadShowMetricsScreen(); + +/** + * Heart image: https://commons.wikimedia.org/wiki/File:Heart_coraz%C3%B3n.svg + * License: CC BY-SA 3.0 + * + * Rendering options: + * Zcash: img2txt -W 50 -H 26 -f utf8 -d none -g 0.7 Z-yellow.orange-logo.png + * Heart: img2txt -W 50 -H 26 -f utf8 -d none 2000px-Heart_corazón.svg.png + */ +const std::string METRICS_ART = +"   \n" +"   \n" +"  .;tt;.   .;t: :t;. \n" +"  :8SX8S;;;:::t%8@S;  .X ;S S; X. \n" +"  t%Xt%%ttt@XXXX@::XXXX%XS  t. X X .t \n" +"  8S;tttt%%tt8 @:;::XXXXXS8   X tt X \n" +"  %S:;;;;:XXX@@8 S;8;;tt;XXXX%8  8 8 \n" +"  8S.:::;;% S:XXXXXX     \n" +"  88....:::% %;::XXXX@    \n" +"  S8888....:%;;;;;;;;;   8t;;;::XXX8    \n" +"   S888888...:::;;;;tX8  ;Xtt;;;;;::XS.  . . \n" +"  t888888888....::::8  @:ttttt;;;;:::X  % % \n" +"  888888888888...:SS  %t%%%ttttt;;;;:X  % % \n" +"  88888888888888.t. ;Stttt%%%ttttt;;;S  % % \n" +"  t888888888888S8 8X;;;tttt%%%tttt;;@  @ @ \n" +"   @8888888888%% %%::::;;;tttt%%%tttt.  S S \n" +"  Stt88888888. %SSSSSSSSSStttt%%%tX  S S \n" +"  8ttt8888S %;;tttt%S   @ @ \n" +"  8%ttt88S %;;;;tt%   8 8 \n" +"  %8ttttt@@@XXX@ %%%%%%%S::;;X8  %. .% \n" +"  88tttt888888 X8888....:S8   .; ;. \n" +"  t8@ttt888@8888@888888S8S  t t \n" +"  :888St8888888%S88;  S S \n" +"   .;tt;:   \n" +"   \n" +"   "; + +const std::string OFFSET = " "; diff --git a/src/miner.cpp b/src/miner.cpp index 7693394e72a..2a5c070b82a 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -12,6 +12,7 @@ #include "consensus/validation.h" #include "hash.h" #include "main.h" +#include "metrics.h" #include "net.h" #include "pow.h" #include "primitives/transaction.h" @@ -437,6 +438,8 @@ static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& rese if (!ProcessNewBlock(state, NULL, pblock, true, NULL)) return error("ZcashMiner: ProcessNewBlock, block not accepted"); + minedBlocks.increment(); + return true; } @@ -555,8 +558,11 @@ void static BitcoinMiner(CWallet *pwallet) SetThreadPriority(THREAD_PRIORITY_LOWEST); // In regression test mode, stop mining after a block is found. - if (chainparams.MineBlocksOnDemand()) + if (chainparams.MineBlocksOnDemand()) { + // Increment here because throwing skips the call below + ehSolverRuns.increment(); throw boost::thread_interrupted(); + } return true; }; @@ -581,6 +587,7 @@ void static BitcoinMiner(CWallet *pwallet) eq.showbsizes(r); } eq.digitK(0); + ehSolverRuns.increment(); // Convert solution indices to byte array (decompress) and pass it to validBlock method. for (size_t s = 0; s < eq.nsols; s++) { @@ -600,8 +607,11 @@ void static BitcoinMiner(CWallet *pwallet) } else { try { // If we find a valid block, we rebuild - if (EhOptimisedSolve(n, k, curr_state, validBlock, cancelled)) + bool found = EhOptimisedSolve(n, k, curr_state, validBlock, cancelled); + ehSolverRuns.increment(); + if (found) { break; + } } catch (EhSolverCancelledException&) { LogPrint("pow", "Equihash solver cancelled\n"); std::lock_guard lock{m_cs}; diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 7f2d01f882d..935d2b20148 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -11,6 +11,7 @@ #include "crypto/equihash.h" #include "init.h" #include "main.h" +#include "metrics.h" #include "miner.h" #include "net.h" #include "pow.h" @@ -193,13 +194,17 @@ Value generate(const Array& params, bool fHelp) pblock->nSolution = soln; return CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus()); }; - if (EhBasicSolveUncancellable(n, k, curr_state, validBlock)) + bool found = EhBasicSolveUncancellable(n, k, curr_state, validBlock); + ehSolverRuns.increment(); + if (found) { goto endloop; + } } endloop: CValidationState state; if (!ProcessNewBlock(state, NULL, pblock, true, NULL)) throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); + minedBlocks.increment(); ++nHeight; blockHashes.push_back(pblock->GetHash().GetHex()); } From 4ace963c80a246ad10c4e4da226d9f71da4cddcb Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sun, 4 Sep 2016 05:51:54 +1200 Subject: [PATCH 02/12] Show important console messages on metrics screen --- src/init.cpp | 1 + src/metrics.cpp | 85 +++++++++++++++++++++++++++++++++++++++++++++++++ src/metrics.h | 1 + 3 files changed, 87 insertions(+) diff --git a/src/init.cpp b/src/init.cpp index a24a1782287..6a9eb6f16f7 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -978,6 +978,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (GetBoolArg("-showmetrics", true) && !fPrintToConsole && !GetBoolArg("-daemon", false)) { // Start the persistent metrics interface + ConnectMetricsScreen(); threadGroup.create_thread(&ThreadShowMetricsScreen); } diff --git a/src/metrics.cpp b/src/metrics.cpp index ad58ab41f11..b835ddfae03 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -5,15 +5,95 @@ #include "metrics.h" #include "chainparams.h" +#include "ui_interface.h" #include "util.h" #include "utiltime.h" #include +#include +#include AtomicCounter transactionsValidated; AtomicCounter ehSolverRuns; AtomicCounter minedBlocks; +boost::synchronized_value> messageBox; +boost::synchronized_value initMessage; +bool loaded = false; + +static bool metrics_ThreadSafeMessageBox(const std::string& message, + const std::string& caption, + unsigned int style) +{ + std::string strCaption; + // Check for usage of predefined caption + switch (style) { + case CClientUIInterface::MSG_ERROR: + strCaption += _("Error"); + break; + case CClientUIInterface::MSG_WARNING: + strCaption += _("Warning"); + break; + case CClientUIInterface::MSG_INFORMATION: + strCaption += _("Information"); + break; + default: + strCaption += caption; // Use supplied caption (can be empty) + } + + boost::strict_lock_ptr> u = messageBox.synchronize(); + u->push_back(strCaption + ": " + message); + if (u->size() > 5) { + u->pop_back(); + } +} + +static void metrics_InitMessage(const std::string& message) +{ + *initMessage = message; +} + +void ConnectMetricsScreen() +{ + uiInterface.ThreadSafeMessageBox.disconnect_all_slots(); + uiInterface.ThreadSafeMessageBox.connect(metrics_ThreadSafeMessageBox); + uiInterface.InitMessage.disconnect_all_slots(); + uiInterface.InitMessage.connect(metrics_InitMessage); +} + +int printMessageBox() +{ + boost::strict_lock_ptr> u = messageBox.synchronize(); + + if (u->size() == 0) { + return 0; + } + + std::cout << std::endl; + std::cout << "Messages:" << std::endl; + for (auto it = u->cbegin(); it != u->cend(); ++it) { + std::cout << *it << std::endl; + } + return 2 + u->size(); +} + +int printInitMessage() +{ + if (loaded) { + return 0; + } + + std::string msg = *initMessage; + std::cout << std::endl; + std::cout << "Init message: " << msg << std::endl; + + if (msg == "Done loading") { + loaded = true; + } + + return 2; +} + void ThreadShowMetricsScreen() { // Make this thread recognisable as the metrics screen thread @@ -53,6 +133,7 @@ void ThreadShowMetricsScreen() int64_t nStart = GetTime(); while (true) { + // Number of lines that are always displayed int lines = 4; // Erase below current position @@ -91,6 +172,10 @@ void ThreadShowMetricsScreen() } } + // Messages + lines += printMessageBox(); + lines += printInitMessage(); + // Explain how to exit std::cout << std::endl; std::cout << "[Hit Ctrl+C to exit] [Set 'showmetrics=0' to hide]" << std::endl;; diff --git a/src/metrics.h b/src/metrics.h index f1fa13d58f0..a9713f0e209 100644 --- a/src/metrics.h +++ b/src/metrics.h @@ -27,6 +27,7 @@ extern AtomicCounter transactionsValidated; extern AtomicCounter ehSolverRuns; extern AtomicCounter minedBlocks; +void ConnectMetricsScreen(); void ThreadShowMetricsScreen(); /** From d934e689671ab18a49bcf2a0e747d4b3e89e17d1 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sun, 4 Sep 2016 15:01:01 +1200 Subject: [PATCH 03/12] Fit metrics screen into an 80-column terminal without wrapping --- src/metrics.cpp | 18 ++++++++--------- src/metrics.h | 52 +++++++++++++++++++++---------------------------- 2 files changed, 31 insertions(+), 39 deletions(-) diff --git a/src/metrics.cpp b/src/metrics.cpp index b835ddfae03..60ae8dae045 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -107,8 +107,8 @@ void ThreadShowMetricsScreen() std::cout << std::endl; // Thank you text - std::cout << OFFSET << "Thank you for running a Zcash node!" << std::endl; - std::cout << OFFSET << "By running this node, you're contributing to the social good :)" << std::endl; + std::cout << "Thank you for running a Zcash node!" << std::endl; + std::cout << "By running this node, you're contributing to the social good :)" << std::endl; std::cout << std::endl; // Miner status @@ -122,10 +122,10 @@ void ThreadShowMetricsScreen() else nThreads = boost::thread::hardware_concurrency(); } - std::cout << OFFSET << "You are running " << nThreads << " mining threads." << std::endl; + std::cout << "You are running " << nThreads << " mining threads." << std::endl; } else { - std::cout << OFFSET << "You are currently not mining." << std::endl; - std::cout << OFFSET << "To enable mining, add 'gen=1' to your zcash.conf and restart." << std::endl; + std::cout << "You are currently not mining." << std::endl; + std::cout << "To enable mining, add 'gen=1' to your zcash.conf and restart." << std::endl; } std::cout << std::endl; @@ -147,7 +147,7 @@ void ThreadShowMetricsScreen() int seconds = uptime - (((((days * 24) + hours) * 60) + minutes) * 60); // Display uptime - std::cout << OFFSET << "Since starting this node "; + std::cout << "Since starting this node "; if (days > 0) { std::cout << days << " days, "; } @@ -159,15 +159,15 @@ void ThreadShowMetricsScreen() } std::cout << seconds << " seconds ago:" << std::endl; - std::cout << OFFSET << "- You have validated " << transactionsValidated.get() << " transactions." << std::endl; + std::cout << "- You have validated " << transactionsValidated.get() << " transactions." << std::endl; if (mining) { - std::cout << OFFSET << "- You have completed " << ehSolverRuns.get() << " Equihash solver runs." << std::endl; + std::cout << "- You have completed " << ehSolverRuns.get() << " Equihash solver runs." << std::endl; lines++; int mined = minedBlocks.get(); if (mined > 0) { - std::cout << OFFSET << "- You have mined " << mined << " blocks!" << std::endl; + std::cout << "- You have mined " << mined << " blocks!" << std::endl; lines++; } } diff --git a/src/metrics.h b/src/metrics.h index a9713f0e209..5d8cca0dcba 100644 --- a/src/metrics.h +++ b/src/metrics.h @@ -35,35 +35,27 @@ void ThreadShowMetricsScreen(); * License: CC BY-SA 3.0 * * Rendering options: - * Zcash: img2txt -W 50 -H 26 -f utf8 -d none -g 0.7 Z-yellow.orange-logo.png - * Heart: img2txt -W 50 -H 26 -f utf8 -d none 2000px-Heart_corazón.svg.png + * Zcash: img2txt -W 40 -H 20 -f utf8 -d none -g 0.7 Z-yellow.orange-logo.png + * Heart: img2txt -W 40 -H 20 -f utf8 -d none 2000px-Heart_corazón.svg.png */ const std::string METRICS_ART = -"   \n" -"   \n" -"  .;tt;.   .;t: :t;. \n" -"  :8SX8S;;;:::t%8@S;  .X ;S S; X. \n" -"  t%Xt%%ttt@XXXX@::XXXX%XS  t. X X .t \n" -"  8S;tttt%%tt8 @:;::XXXXXS8   X tt X \n" -"  %S:;;;;:XXX@@8 S;8;;tt;XXXX%8  8 8 \n" -"  8S.:::;;% S:XXXXXX     \n" -"  88....:::% %;::XXXX@    \n" -"  S8888....:%;;;;;;;;;   8t;;;::XXX8    \n" -"   S888888...:::;;;;tX8  ;Xtt;;;;;::XS.  . . \n" -"  t888888888....::::8  @:ttttt;;;;:::X  % % \n" -"  888888888888...:SS  %t%%%ttttt;;;;:X  % % \n" -"  88888888888888.t. ;Stttt%%%ttttt;;;S  % % \n" -"  t888888888888S8 8X;;;tttt%%%tttt;;@  @ @ \n" -"   @8888888888%% %%::::;;;tttt%%%tttt.  S S \n" -"  Stt88888888. %SSSSSSSSSStttt%%%tX  S S \n" -"  8ttt8888S %;;tttt%S   @ @ \n" -"  8%ttt88S %;;;;tt%   8 8 \n" -"  %8ttttt@@@XXX@ %%%%%%%S::;;X8  %. .% \n" -"  88tttt888888 X8888....:S8   .; ;. \n" -"  t8@ttt888@8888@888888S8S  t t \n" -"  :888St8888888%S88;  S S \n" -"   .;tt;:   \n" -"   \n" -"   "; - -const std::string OFFSET = " "; +"   \n" +"   \n" +"  :88SX@888@@X8:  8; %X X% ;8 \n" +"  %%Xt%tt%SSSSS:XXXt@@  X :: :: X \n" +"  @S;;tt%%%t ;;::XXXXSX  % SS % \n" +"  .t:::;;%8888 88888tXXXX8;  S S \n" +"  .%...:::8 8::XXX%;  X X \n" +"  8888...:t888888X 8t;;::XX8   8 8 \n" +" %888888...:::;:8  :Xttt;;;::X@    \n" +" 888888888...:St 8:%%tttt;;;:X  X X \n" +" 88888888888S8  :%;ttt%%tttt;;X  8 8 \n" +" %888888888%t 8S:;;;tt%%%ttt;8  : : \n" +"  8t8888888  S8888888Stt%%%t@   :: :: \n" +"  .@tt888@ 8;;ttt@;  t t \n" +"  .8ttt8@SSSSS SXXXX%:;;;X;  8 8 \n" +"  X8ttt8888% %88...::X8   X. .X \n" +"  %8@tt88;8888%8888%8X   :; ;: \n" +"  :@888@XXX@888:  tt \n" +"   \n" +"   "; From 4482bd8fd70fc5b9ef2bf94ba45cc80514de642b Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sun, 4 Sep 2016 15:04:22 +1200 Subject: [PATCH 04/12] Adjust copy --- src/metrics.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/metrics.cpp b/src/metrics.cpp index 60ae8dae045..51f17d6e101 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -107,8 +107,8 @@ void ThreadShowMetricsScreen() std::cout << std::endl; // Thank you text - std::cout << "Thank you for running a Zcash node!" << std::endl; - std::cout << "By running this node, you're contributing to the social good :)" << std::endl; + std::cout << "Thank you for running a Zcash node!" << std::endl; + std::cout << "You're helping to strengthen the network and contributing to a social good :)" << std::endl; std::cout << std::endl; // Miner status @@ -178,7 +178,7 @@ void ThreadShowMetricsScreen() // Explain how to exit std::cout << std::endl; - std::cout << "[Hit Ctrl+C to exit] [Set 'showmetrics=0' to hide]" << std::endl;; + std::cout << "[Press Ctrl+C to exit] [Set 'showmetrics=0' to hide]" << std::endl;; boost::this_thread::interruption_point(); MilliSleep(1000); From d30273f9198de69a69008db2722e380ebeb08313 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sun, 4 Sep 2016 15:18:44 +1200 Subject: [PATCH 05/12] Split out screen sections into separate functions --- src/metrics.cpp | 119 +++++++++++++++++++++++++++--------------------- 1 file changed, 66 insertions(+), 53 deletions(-) diff --git a/src/metrics.cpp b/src/metrics.cpp index 51f17d6e101..621f50ce0bf 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -61,6 +61,67 @@ void ConnectMetricsScreen() uiInterface.InitMessage.connect(metrics_InitMessage); } +void printMiningStatus(bool mining) +{ + 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(); + } + std::cout << "You are running " << nThreads << " mining threads." << std::endl; + } else { + std::cout << "You are currently not mining." << std::endl; + std::cout << "To enable mining, add 'gen=1' to your zcash.conf and restart." << std::endl; + } + std::cout << std::endl; +} + +int printMetrics(int64_t nStart, bool mining) +{ + // Number of lines that are always displayed + int lines = 3; + + // Calculate uptime + int64_t uptime = GetTime() - nStart; + int days = uptime / (24 * 60 * 60); + int hours = (uptime - (days * 24 * 60 * 60)) / (60 * 60); + int minutes = (uptime - (((days * 24) + hours) * 60 * 60)) / 60; + int seconds = uptime - (((((days * 24) + hours) * 60) + minutes) * 60); + + // Display uptime + std::cout << "Since starting this node "; + if (days > 0) { + std::cout << days << " days, "; + } + if (hours > 0) { + std::cout << hours << " hours, "; + } + if (minutes > 0) { + std::cout << minutes << " minutes, "; + } + std::cout << seconds << " seconds ago:" << std::endl; + + std::cout << "- You have validated " << transactionsValidated.get() << " transactions." << std::endl; + + if (mining) { + std::cout << "- You have completed " << ehSolverRuns.get() << " Equihash solver runs." << std::endl; + lines++; + + int mined = minedBlocks.get(); + if (mined > 0) { + std::cout << "- You have mined " << mined << " blocks!" << std::endl; + lines++; + } + } + std::cout << std::endl; + + return lines; +} + int printMessageBox() { boost::strict_lock_ptr> u = messageBox.synchronize(); @@ -69,11 +130,11 @@ int printMessageBox() return 0; } - std::cout << std::endl; std::cout << "Messages:" << std::endl; for (auto it = u->cbegin(); it != u->cend(); ++it) { std::cout << *it << std::endl; } + std::cout << std::endl; return 2 + u->size(); } @@ -84,8 +145,8 @@ int printInitMessage() } std::string msg = *initMessage; - std::cout << std::endl; std::cout << "Init message: " << msg << std::endl; + std::cout << std::endl; if (msg == "Done loading") { loaded = true; @@ -113,71 +174,23 @@ void ThreadShowMetricsScreen() // Miner status bool mining = GetBoolArg("-gen", false); - 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(); - } - std::cout << "You are running " << nThreads << " mining threads." << std::endl; - } else { - std::cout << "You are currently not mining." << std::endl; - std::cout << "To enable mining, add 'gen=1' to your zcash.conf and restart." << std::endl; - } - std::cout << std::endl; + printMiningStatus(mining); // Count uptime int64_t nStart = GetTime(); while (true) { // Number of lines that are always displayed - int lines = 4; + int lines = 1; // Erase below current position std::cout << "\e[J"; - // Calculate uptime - int64_t uptime = GetTime() - nStart; - int days = uptime / (24 * 60 * 60); - int hours = (uptime - (days * 24 * 60 * 60)) / (60 * 60); - int minutes = (uptime - (((days * 24) + hours) * 60 * 60)) / 60; - int seconds = uptime - (((((days * 24) + hours) * 60) + minutes) * 60); - - // Display uptime - std::cout << "Since starting this node "; - if (days > 0) { - std::cout << days << " days, "; - } - if (hours > 0) { - std::cout << hours << " hours, "; - } - if (minutes > 0) { - std::cout << minutes << " minutes, "; - } - std::cout << seconds << " seconds ago:" << std::endl; - - std::cout << "- You have validated " << transactionsValidated.get() << " transactions." << std::endl; - - if (mining) { - std::cout << "- You have completed " << ehSolverRuns.get() << " Equihash solver runs." << std::endl; - lines++; - - int mined = minedBlocks.get(); - if (mined > 0) { - std::cout << "- You have mined " << mined << " blocks!" << std::endl; - lines++; - } - } - - // Messages + lines += printMetrics(nStart, mining); lines += printMessageBox(); lines += printInitMessage(); // Explain how to exit - std::cout << std::endl; std::cout << "[Press Ctrl+C to exit] [Set 'showmetrics=0' to hide]" << std::endl;; boost::this_thread::interruption_point(); From 0ddd6d1cd8a3bc481d81d5f16279d055a01a95bc Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sun, 4 Sep 2016 15:31:50 +1200 Subject: [PATCH 06/12] Tag metrics strings for translation --- src/metrics.cpp | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/metrics.cpp b/src/metrics.cpp index 621f50ce0bf..3ee6f61fc84 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -72,10 +72,10 @@ void printMiningStatus(bool mining) else nThreads = boost::thread::hardware_concurrency(); } - std::cout << "You are running " << nThreads << " mining threads." << std::endl; + std::cout << strprintf(_("You are running %d mining threads."), nThreads) << std::endl; } else { - std::cout << "You are currently not mining." << std::endl; - std::cout << "To enable mining, add 'gen=1' to your zcash.conf and restart." << std::endl; + std::cout << _("You are currently not mining.") << std::endl; + std::cout << _("To enable mining, add 'gen=1' to your zcash.conf and restart.") << std::endl; } std::cout << std::endl; } @@ -93,27 +93,27 @@ int printMetrics(int64_t nStart, bool mining) int seconds = uptime - (((((days * 24) + hours) * 60) + minutes) * 60); // Display uptime - std::cout << "Since starting this node "; + std::string duration; if (days > 0) { - std::cout << days << " days, "; - } - if (hours > 0) { - std::cout << hours << " hours, "; - } - if (minutes > 0) { - std::cout << minutes << " minutes, "; + duration = strprintf(_("%d days, %d hours, %d minutes, %d seconds"), days, hours, minutes, seconds); + } else if (hours > 0) { + duration = strprintf(_("%d hours, %d minutes, %d seconds"), hours, minutes, seconds); + } else if (minutes > 0) { + duration = strprintf(_("%d minutes, %d seconds"), minutes, seconds); + } else { + duration = strprintf(_("%d seconds"), seconds); } - std::cout << seconds << " seconds ago:" << std::endl; + std::cout << strprintf(_("Since starting this node %s ago:"), duration) << std::endl; - std::cout << "- You have validated " << transactionsValidated.get() << " transactions." << std::endl; + std::cout << "- " << strprintf(_("You have validated %d transactions."), transactionsValidated.get()) << std::endl; if (mining) { - std::cout << "- You have completed " << ehSolverRuns.get() << " Equihash solver runs." << std::endl; + std::cout << "- " << strprintf(_("You have completed %d Equihash solver runs."), ehSolverRuns.get()) << std::endl; lines++; int mined = minedBlocks.get(); if (mined > 0) { - std::cout << "- You have mined " << mined << " blocks!" << std::endl; + std::cout << "- " << strprintf(_("You have mined %d blocks!"), mined) << std::endl; lines++; } } @@ -130,7 +130,7 @@ int printMessageBox() return 0; } - std::cout << "Messages:" << std::endl; + std::cout << _("Messages:") << std::endl; for (auto it = u->cbegin(); it != u->cend(); ++it) { std::cout << *it << std::endl; } @@ -145,10 +145,10 @@ int printInitMessage() } std::string msg = *initMessage; - std::cout << "Init message: " << msg << std::endl; + std::cout << _("Init message:") << " " << msg << std::endl; std::cout << std::endl; - if (msg == "Done loading") { + if (msg == _("Done loading")) { loaded = true; } @@ -168,8 +168,8 @@ void ThreadShowMetricsScreen() std::cout << std::endl; // Thank you text - std::cout << "Thank you for running a Zcash node!" << std::endl; - std::cout << "You're helping to strengthen the network and contributing to a social good :)" << std::endl; + std::cout << _("Thank you for running a Zcash node!") << std::endl; + std::cout << _("You're helping to strengthen the network and contributing to a social good :)") << std::endl; std::cout << std::endl; // Miner status @@ -191,7 +191,7 @@ void ThreadShowMetricsScreen() lines += printInitMessage(); // Explain how to exit - std::cout << "[Press Ctrl+C to exit] [Set 'showmetrics=0' to hide]" << std::endl;; + std::cout << "[" << _("Press Ctrl+C to exit") << "] [" << _("Set 'showmetrics=0' to hide") << "]" << std::endl;; boost::this_thread::interruption_point(); MilliSleep(1000); From db853f8a4640b8a84186f97a78ea47f1a51c74f9 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sun, 4 Sep 2016 15:40:28 +1200 Subject: [PATCH 07/12] Handle wrapping of potentially long lines --- src/metrics.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/metrics.cpp b/src/metrics.cpp index 3ee6f61fc84..8b41b5bfcf5 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -12,6 +12,7 @@ #include #include #include +#include AtomicCounter transactionsValidated; AtomicCounter ehSolverRuns; @@ -80,7 +81,7 @@ void printMiningStatus(bool mining) std::cout << std::endl; } -int printMetrics(int64_t nStart, bool mining) +int printMetrics(size_t cols, int64_t nStart, bool mining) { // Number of lines that are always displayed int lines = 3; @@ -103,7 +104,9 @@ int printMetrics(int64_t nStart, bool mining) } else { duration = strprintf(_("%d seconds"), seconds); } - std::cout << strprintf(_("Since starting this node %s ago:"), duration) << std::endl; + std::string strDuration = strprintf(_("Since starting this node %s ago:"), duration); + std::cout << strDuration << std::endl; + lines += (strDuration.size() / cols); std::cout << "- " << strprintf(_("You have validated %d transactions."), transactionsValidated.get()) << std::endl; @@ -122,7 +125,7 @@ int printMetrics(int64_t nStart, bool mining) return lines; } -int printMessageBox() +int printMessageBox(size_t cols) { boost::strict_lock_ptr> u = messageBox.synchronize(); @@ -130,12 +133,15 @@ int printMessageBox() return 0; } + int lines = 2 + u->size(); std::cout << _("Messages:") << std::endl; for (auto it = u->cbegin(); it != u->cend(); ++it) { std::cout << *it << std::endl; + // Handle wrapped lines + lines += (it->size() / cols); } std::cout << std::endl; - return 2 + u->size(); + return lines; } int printInitMessage() @@ -183,11 +189,15 @@ void ThreadShowMetricsScreen() // Number of lines that are always displayed int lines = 1; + // Get current window size + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + // Erase below current position std::cout << "\e[J"; - lines += printMetrics(nStart, mining); - lines += printMessageBox(); + lines += printMetrics(w.ws_col, nStart, mining); + lines += printMessageBox(w.ws_col); lines += printInitMessage(); // Explain how to exit From e7d59bbc1208b8eaaa1447885c3da222f4a1c495 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 5 Sep 2016 10:54:15 +1200 Subject: [PATCH 08/12] Add average hash rate to metrics --- src/metrics.cpp | 6 +++++- src/metrics.h | 1 + src/miner.cpp | 1 + src/rpcmining.cpp | 1 + 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/metrics.cpp b/src/metrics.cpp index 8b41b5bfcf5..4d339b91927 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -16,6 +16,7 @@ AtomicCounter transactionsValidated; AtomicCounter ehSolverRuns; +AtomicCounter solutionTargetChecks; AtomicCounter minedBlocks; boost::synchronized_value> messageBox; @@ -111,8 +112,11 @@ int printMetrics(size_t cols, int64_t nStart, bool mining) std::cout << "- " << strprintf(_("You have validated %d transactions."), transactionsValidated.get()) << std::endl; if (mining) { + double hps = uptime > 0 ? (double)solutionTargetChecks.get() / uptime : 0; + std::string strHps = strprintf("%.4f H/s", hps); + std::cout << "- " << strprintf(_("You have contributed %s on average to the network hash rate."), strHps) << std::endl; std::cout << "- " << strprintf(_("You have completed %d Equihash solver runs."), ehSolverRuns.get()) << std::endl; - lines++; + lines += 2; int mined = minedBlocks.get(); if (mined > 0) { diff --git a/src/metrics.h b/src/metrics.h index 5d8cca0dcba..4a2ca2264de 100644 --- a/src/metrics.h +++ b/src/metrics.h @@ -25,6 +25,7 @@ struct AtomicCounter { extern AtomicCounter transactionsValidated; extern AtomicCounter ehSolverRuns; +extern AtomicCounter solutionTargetChecks; extern AtomicCounter minedBlocks; void ConnectMetricsScreen(); diff --git a/src/miner.cpp b/src/miner.cpp index 2a5c070b82a..bde9babd59c 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -541,6 +541,7 @@ void static BitcoinMiner(CWallet *pwallet) // Write the solution to the hash and compute the result. LogPrint("pow", "- Checking solution against target\n"); pblock->nSolution = soln; + solutionTargetChecks.increment(); if (UintToArith256(pblock->GetHash()) > hashTarget) { return false; diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 935d2b20148..faa02b6dbae 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -192,6 +192,7 @@ Value generate(const Array& params, bool fHelp) std::function)> validBlock = [&pblock](std::vector soln) { pblock->nSolution = soln; + solutionTargetChecks.increment(); return CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus()); }; bool found = EhBasicSolveUncancellable(n, k, curr_state, validBlock); From f8ada2435bd3f6b7a1165eae5fdfd6ac8a96f018 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 5 Sep 2016 10:54:25 +1200 Subject: [PATCH 09/12] Be excited about validating transactions! --- src/metrics.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metrics.cpp b/src/metrics.cpp index 4d339b91927..bb1fe66bcfe 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -109,7 +109,7 @@ int printMetrics(size_t cols, int64_t nStart, bool mining) std::cout << strDuration << std::endl; lines += (strDuration.size() / cols); - std::cout << "- " << strprintf(_("You have validated %d transactions."), transactionsValidated.get()) << std::endl; + std::cout << "- " << strprintf(_("You have validated %d transactions!"), transactionsValidated.get()) << std::endl; if (mining) { double hps = uptime > 0 ? (double)solutionTargetChecks.get() / uptime : 0; From 199b3aafd3780574456530f2296de805297e8158 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 5 Oct 2016 18:45:00 -0500 Subject: [PATCH 10/12] Use solutions per second (Sol/s) Part of #1422 --- src/metrics.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/metrics.cpp b/src/metrics.cpp index bb1fe66bcfe..32fc4ba05e5 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -112,9 +112,9 @@ int printMetrics(size_t cols, int64_t nStart, bool mining) std::cout << "- " << strprintf(_("You have validated %d transactions!"), transactionsValidated.get()) << std::endl; if (mining) { - double hps = uptime > 0 ? (double)solutionTargetChecks.get() / uptime : 0; - std::string strHps = strprintf("%.4f H/s", hps); - std::cout << "- " << strprintf(_("You have contributed %s on average to the network hash rate."), strHps) << std::endl; + double solps = uptime > 0 ? (double)solutionTargetChecks.get() / uptime : 0; + std::string strSolps = strprintf("%.4f Sol/s", solps); + std::cout << "- " << strprintf(_("You have contributed %s on average to the network solution rate."), strSolps) << std::endl; std::cout << "- " << strprintf(_("You have completed %d Equihash solver runs."), ehSolverRuns.get()) << std::endl; lines += 2; From dccc140bf1c287aa646c9069f0068a142e8841c3 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sat, 22 Oct 2016 15:59:44 -0500 Subject: [PATCH 11/12] Comment out print statements in tromp's solver This prevents the solver interfering with the metrics screen. --- src/pow/tromp/equi_miner.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/pow/tromp/equi_miner.h b/src/pow/tromp/equi_miner.h index 2f6531fe8fa..9559c178e70 100644 --- a/src/pow/tromp/equi_miner.h +++ b/src/pow/tromp/equi_miner.h @@ -300,7 +300,7 @@ struct equi { } for (u32 i=0; i < 65; i++) { #ifdef HIST - printf(" %d:%d", i, binsizes[i]); +// printf(" %d:%d", i, binsizes[i]); #else #ifdef SPARK u32 sparks = binsizes[i] / SPARKSCALE; @@ -309,10 +309,10 @@ struct equi { for (u32 bs = binsizes[i]; bs; bs >>= 1) sparks++; sparks = sparks * 7 / SPARKSCALE; #endif - printf("\342\226%c", '\201' + sparks); +// printf("\342\226%c", '\201' + sparks); #endif } - printf("\n"); +// printf("\n"); #endif } @@ -590,7 +590,7 @@ nc++, candidate(tree(bucketid, s0, s1)); } } } -printf(" %d candidates ", nc); +//printf(" %d candidates ", nc); } }; @@ -603,7 +603,7 @@ typedef struct { void barrier(pthread_barrier_t *barry) { const int rc = pthread_barrier_wait(barry); if (rc != 0 && rc != PTHREAD_BARRIER_SERIAL_THREAD) { - printf("Could not wait on barrier\n"); +// printf("Could not wait on barrier\n"); pthread_exit(NULL); } } @@ -613,7 +613,7 @@ void *worker(void *vp) { equi *eq = tp->eq; if (tp->id == 0) - printf("Digit 0\n"); +// printf("Digit 0\n"); barrier(&eq->barry); eq->digit0(tp->id); barrier(&eq->barry); @@ -624,19 +624,19 @@ void *worker(void *vp) { barrier(&eq->barry); for (u32 r = 1; r < WK; r++) { if (tp->id == 0) - printf("Digit %d", r); +// printf("Digit %d", r); barrier(&eq->barry); r&1 ? eq->digitodd(r, tp->id) : eq->digiteven(r, tp->id); barrier(&eq->barry); if (tp->id == 0) { - printf(" x%d b%d h%d\n", eq->xfull, eq->bfull, eq->hfull); +// printf(" x%d b%d h%d\n", eq->xfull, eq->bfull, eq->hfull); eq->xfull = eq->bfull = eq->hfull = 0; eq->showbsizes(r); } barrier(&eq->barry); } if (tp->id == 0) - printf("Digit %d\n", WK); +// printf("Digit %d\n", WK); eq->digitK(tp->id); barrier(&eq->barry); pthread_exit(NULL); From 02a4ace02c3d8a5fd992d63fa788d9dba85b023a Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Sun, 23 Oct 2016 01:05:57 +0100 Subject: [PATCH 12/12] Disable metrics screen in RPC tests Author: Jack Grigg Signed-off-by: Daira Hopwood --- qa/rpc-tests/test_framework/util.py | 1 + 1 file changed, 1 insertion(+) diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index a8e260f9502..bfb9bddf14b 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -65,6 +65,7 @@ def initialize_datadir(dirname, n): os.makedirs(datadir) with open(os.path.join(datadir, "zcash.conf"), 'w') as f: f.write("regtest=1\n"); + f.write("showmetrics=0\n"); f.write("rpcuser=rt\n"); f.write("rpcpassword=rt\n"); f.write("port="+str(p2p_port(n))+"\n");