Browse Source

Add a persistent screen showing basic node metrics

The screen is implemented using ANSI Escape sequences.

Closes #1331
pull/4/head
Jack Grigg 8 years ago
parent
commit
a6df7ab567
No known key found for this signature in database GPG Key ID: 6A6914DAFBEA00DA
  1. 2
      src/Makefile.am
  2. 6
      src/init.cpp
  3. 6
      src/main.cpp
  4. 104
      src/metrics.cpp
  5. 68
      src/metrics.h
  6. 14
      src/miner.cpp
  7. 7
      src/rpcmining.cpp

2
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 \

6
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<CScheduler::Function>, "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

6
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 {

104
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 <boost/thread.hpp>
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";
}
}

68
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 <atomic>
#include <string>
struct AtomicCounter {
std::atomic<int> 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 = " ";

14
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<std::mutex> lock{m_cs};

7
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());
}

Loading…
Cancel
Save