diff --git a/src/Makefile.gtest.include b/src/Makefile.gtest.include index 3941192b5..589293c9c 100644 --- a/src/Makefile.gtest.include +++ b/src/Makefile.gtest.include @@ -19,6 +19,7 @@ zcash_gtest_SOURCES = \ gtest/test_keystore.cpp \ gtest/test_noteencryption.cpp \ gtest/test_merkletree.cpp \ + gtest/test_metrics.cpp \ gtest/test_pow.cpp \ gtest/test_random.cpp \ gtest/test_rpc.cpp \ diff --git a/src/gtest/test_metrics.cpp b/src/gtest/test_metrics.cpp new file mode 100644 index 000000000..33c33d4d4 --- /dev/null +++ b/src/gtest/test_metrics.cpp @@ -0,0 +1,30 @@ +#include + +#include "metrics.h" +#include "utiltime.h" + + +TEST(Metrics, GetLocalSolPS) { + SetMockTime(100); + MarkStartTime(); + + // No time has passed + EXPECT_EQ(0, GetLocalSolPS()); + + // Increment time + SetMockTime(101); + EXPECT_EQ(0, GetLocalSolPS()); + + // Increment solutions + solutionTargetChecks.increment(); + EXPECT_EQ(1, GetLocalSolPS()); + + // Increment time + SetMockTime(102); + EXPECT_EQ(0.5, GetLocalSolPS()); + + // Increment solutions + solutionTargetChecks.increment(); + solutionTargetChecks.increment(); + EXPECT_EQ(1.5, GetLocalSolPS()); +} diff --git a/src/init.cpp b/src/init.cpp index 6dcaa314a..e9a48f47f 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -984,6 +984,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) CScheduler::Function serviceLoop = boost::bind(&CScheduler::serviceQueue, &scheduler); threadGroup.create_thread(boost::bind(&TraceThread, "scheduler", serviceLoop)); + // Count uptime + MarkStartTime(); + if ((chainparams.NetworkIDString() != "regtest") && GetBoolArg("-showmetrics", isatty(STDOUT_FILENO)) && !fPrintToConsole && !GetBoolArg("-daemon", false)) { diff --git a/src/metrics.cpp b/src/metrics.cpp index eb546d79d..053538660 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -19,6 +19,7 @@ CCriticalSection cs_metrics; +boost::synchronized_value nNodeStartTime; AtomicCounter transactionsValidated; AtomicCounter ehSolverRuns; AtomicCounter solutionTargetChecks; @@ -39,6 +40,26 @@ void TrackMinedBlock(uint256 hash) trackedBlocks->push_back(hash); } +void MarkStartTime() +{ + *nNodeStartTime = GetTime(); +} + +int64_t GetUptime() +{ + return GetTime() - *nNodeStartTime; +} + +double GetLocalSolPS_INTERNAL(int64_t uptime) +{ + return uptime > 0 ? (double)solutionTargetChecks.get() / uptime : 0; +} + +double GetLocalSolPS() +{ + return GetLocalSolPS_INTERNAL(GetUptime()); +} + static bool metrics_ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style) @@ -118,13 +139,13 @@ int printMiningStatus(bool mining) return lines; } -int printMetrics(size_t cols, int64_t nStart, bool mining) +int printMetrics(size_t cols, bool mining) { // Number of lines that are always displayed int lines = 3; // Calculate uptime - int64_t uptime = GetTime() - nStart; + int64_t uptime = GetUptime(); int days = uptime / (24 * 60 * 60); int hours = (uptime - (days * 24 * 60 * 60)) / (60 * 60); int minutes = (uptime - (((days * 24) + hours) * 60 * 60)) / 60; @@ -155,7 +176,7 @@ int printMetrics(size_t cols, int64_t nStart, bool mining) } if (mining && loaded) { - double solps = uptime > 0 ? (double)solutionTargetChecks.get() / uptime : 0; + double solps = GetLocalSolPS_INTERNAL(uptime); 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; @@ -274,9 +295,6 @@ void ThreadShowMetricsScreen() std::cout << std::endl; } - // Count uptime - int64_t nStart = GetTime(); - while (true) { // Number of lines that are always displayed int lines = 1; @@ -303,7 +321,7 @@ void ThreadShowMetricsScreen() lines += printNetworkStats(); } lines += printMiningStatus(mining); - lines += printMetrics(cols, nStart, mining); + lines += printMetrics(cols, mining); lines += printMessageBox(cols); lines += printInitMessage(); diff --git a/src/metrics.h b/src/metrics.h index 2c5e7bd2c..2851178b6 100644 --- a/src/metrics.h +++ b/src/metrics.h @@ -31,6 +31,9 @@ extern AtomicCounter solutionTargetChecks; void TrackMinedBlock(uint256 hash); +void MarkStartTime(); +double GetLocalSolPS(); + void ConnectMetricsScreen(); void ThreadShowMetricsScreen(); diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index d6bd4dd3e..d58e70adc 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -74,19 +74,60 @@ int64_t GetNetworkHashPS(int lookup, int height) { return (int64_t)(workDiff.getdouble() / timeDiff); } -Value getnetworkhashps(const Array& params, bool fHelp) +Value getlocalsolps(const Array& params, bool fHelp) +{ + if (fHelp) + throw runtime_error( + "getlocalsolps\n" + "\nReturns the average local solutions per second since this node was started.\n" + "This is the same information shown on the metrics screen (if enabled).\n" + "\nResult:\n" + "xxx.xxxxx (numeric) Solutions per second average\n" + "\nExamples:\n" + + HelpExampleCli("getlocalsolps", "") + + HelpExampleRpc("getlocalsolps", "") + ); + + LOCK(cs_main); + return GetLocalSolPS(); +} + +Value getnetworksolps(const Array& params, bool fHelp) { if (fHelp || params.size() > 2) throw runtime_error( - "getnetworkhashps ( blocks height )\n" - "\nReturns the estimated network hashes per second based on the last n blocks.\n" + "getnetworksolps ( blocks height )\n" + "\nReturns the estimated network solutions per second based on the last n blocks.\n" "Pass in [blocks] to override # of blocks, -1 specifies over difficulty averaging window.\n" "Pass in [height] to estimate the network speed at the time when a certain block was found.\n" "\nArguments:\n" "1. blocks (numeric, optional, default=120) The number of blocks, or -1 for blocks over difficulty averaging window.\n" "2. height (numeric, optional, default=-1) To estimate at the time of the given height.\n" "\nResult:\n" - "x (numeric) Hashes per second estimated\n" + "x (numeric) Solutions per second estimated\n" + "\nExamples:\n" + + HelpExampleCli("getnetworksolps", "") + + HelpExampleRpc("getnetworksolps", "") + ); + + LOCK(cs_main); + return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1); +} + +Value getnetworkhashps(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 2) + throw runtime_error( + "getnetworkhashps ( blocks height )\n" + "\nDEPRECATED - left for backwards-compatibility. Use getnetworksolps instead.\n" + "\nReturns the estimated network solutions per second based on the last n blocks.\n" + "Pass in [blocks] to override # of blocks, -1 specifies over difficulty averaging window.\n" + "Pass in [height] to estimate the network speed at the time when a certain block was found.\n" + "\nArguments:\n" + "1. blocks (numeric, optional, default=120) The number of blocks, or -1 for blocks over difficulty averaging window.\n" + "2. height (numeric, optional, default=-1) To estimate at the time of the given height.\n" + "\nResult:\n" + "x (numeric) Solutions per second estimated\n" "\nExamples:\n" + HelpExampleCli("getnetworkhashps", "") + HelpExampleRpc("getnetworkhashps", "") @@ -275,6 +316,8 @@ Value getmininginfo(const Array& params, bool fHelp) " \"errors\": \"...\" (string) Current errors\n" " \"generate\": true|false (boolean) If the generation is on or off (see getgenerate or setgenerate calls)\n" " \"genproclimit\": n (numeric) The processor limit for generation. -1 if no generation. (see getgenerate or setgenerate calls)\n" + " \"localsolps\": xxx.xxxxx (numeric) The average local solution rate in Sol/s since this node was started\n" + " \"networksolps\": x (numeric) The estimated network solution rate in Sol/s\n" " \"pooledtx\": n (numeric) The size of the mem pool\n" " \"testnet\": true|false (boolean) If using testnet or not\n" " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n" @@ -294,7 +337,9 @@ Value getmininginfo(const Array& params, bool fHelp) obj.push_back(Pair("difficulty", (double)GetNetworkDifficulty())); obj.push_back(Pair("errors", GetWarnings("statusbar"))); obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1))); - obj.push_back(Pair("networkhashps", getnetworkhashps(params, false))); + obj.push_back(Pair("localsolps" , getlocalsolps(params, false))); + obj.push_back(Pair("networksolps", getnetworksolps(params, false))); + obj.push_back(Pair("networkhashps", getnetworksolps(params, false))); obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); obj.push_back(Pair("chain", Params().NetworkIDString())); diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 0418d7519..e354e91a4 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -304,6 +304,8 @@ static const CRPCCommand vRPCCommands[] = /* Mining */ { "mining", "getblocktemplate", &getblocktemplate, true }, { "mining", "getmininginfo", &getmininginfo, true }, + { "mining", "getlocalsolps", &getlocalsolps, true }, + { "mining", "getnetworksolps", &getnetworksolps, true }, { "mining", "getnetworkhashps", &getnetworkhashps, true }, { "mining", "prioritisetransaction", &prioritisetransaction, true }, { "mining", "submitblock", &submitblock, true }, diff --git a/src/rpcserver.h b/src/rpcserver.h index b8eac08c4..fd53bf116 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -169,6 +169,8 @@ extern json_spirit::Value importwallet(const json_spirit::Array& params, bool fH extern json_spirit::Value getgenerate(const json_spirit::Array& params, bool fHelp); // in rpcmining.cpp extern json_spirit::Value setgenerate(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value generate(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getlocalsolps(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getnetworksolps(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getnetworkhashps(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getmininginfo(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value prioritisetransaction(const json_spirit::Array& params, bool fHelp);