]> Git Repo - VerusCoin.git/blobdiff - src/metrics.cpp
Merge pull request #1 from jl777/dev
[VerusCoin.git] / src / metrics.cpp
index cbca89671deb80c6dc1acb6ae03917dbe60a9244..cb9fe245c5d2aa50763ac6eff92b7467553d9fcb 100644 (file)
@@ -5,18 +5,70 @@
 #include "metrics.h"
 
 #include "chainparams.h"
+#include "checkpoints.h"
 #include "main.h"
 #include "ui_interface.h"
 #include "util.h"
 #include "utiltime.h"
 #include "utilmoneystr.h"
+#include "utilstrencodings.h"
 
 #include <boost/thread.hpp>
 #include <boost/thread/synchronized_value.hpp>
 #include <string>
+#ifdef _WIN32
+#include <io.h>
+#include <windows.h>
+#else
 #include <sys/ioctl.h>
+#endif
 #include <unistd.h>
 
+void AtomicTimer::start()
+{
+    std::unique_lock<std::mutex> lock(mtx);
+    if (threads < 1) {
+        start_time = GetTime();
+    }
+    ++threads;
+}
+
+void AtomicTimer::stop()
+{
+    std::unique_lock<std::mutex> lock(mtx);
+    // Ignore excess calls to stop()
+    if (threads > 0) {
+        --threads;
+        if (threads < 1) {
+            int64_t time_span = GetTime() - start_time;
+            total_time += time_span;
+        }
+    }
+}
+
+bool AtomicTimer::running()
+{
+    std::unique_lock<std::mutex> lock(mtx);
+    return threads > 0;
+}
+
+uint64_t AtomicTimer::threadCount()
+{
+    std::unique_lock<std::mutex> lock(mtx);
+    return threads;
+}
+
+double AtomicTimer::rate(const AtomicCounter& count)
+{
+    std::unique_lock<std::mutex> lock(mtx);
+    int64_t duration = total_time;
+    if (threads > 0) {
+        // Timer is running, so get the latest count
+        duration += GetTime() - start_time;
+    }
+    return duration > 0 ? (double)count.get() / duration : 0;
+}
+
 CCriticalSection cs_metrics;
 
 boost::synchronized_value<int64_t> nNodeStartTime;
@@ -25,6 +77,7 @@ AtomicCounter transactionsValidated;
 AtomicCounter ehSolverRuns;
 AtomicCounter solutionTargetChecks;
 AtomicCounter minedBlocks;
+AtomicTimer miningTimer;
 
 boost::synchronized_value<std::list<uint256>> trackedBlocks;
 
@@ -51,14 +104,39 @@ int64_t GetUptime()
     return GetTime() - *nNodeStartTime;
 }
 
-double GetLocalSolPS_INTERNAL(int64_t uptime)
+double GetLocalSolPS()
 {
-    return uptime > 0 ? (double)solutionTargetChecks.get() / uptime : 0;
+    return miningTimer.rate(solutionTargetChecks);
 }
 
-double GetLocalSolPS()
+int EstimateNetHeightInner(int height, int64_t tipmediantime,
+                           int heightLastCheckpoint, int64_t timeLastCheckpoint,
+                           int64_t genesisTime, int64_t targetSpacing)
 {
-    return GetLocalSolPS_INTERNAL(GetUptime());
+    // We average the target spacing with the observed spacing to the last
+    // checkpoint (either from below or above depending on the current height),
+    // and use that to estimate the current network height.
+    int medianHeight = height > CBlockIndex::nMedianTimeSpan ?
+            height - (1 + ((CBlockIndex::nMedianTimeSpan - 1) / 2)) :
+            height / 2;
+    double checkpointSpacing = medianHeight > heightLastCheckpoint ?
+            (double (tipmediantime - timeLastCheckpoint)) / (medianHeight - heightLastCheckpoint) :
+            (double (timeLastCheckpoint - genesisTime)) / heightLastCheckpoint;
+    double averageSpacing = (targetSpacing + checkpointSpacing) / 2;
+    int netheight = medianHeight + ((GetTime() - tipmediantime) / averageSpacing);
+    // Round to nearest ten to reduce noise
+    return ((netheight + 5) / 10) * 10;
+}
+
+int EstimateNetHeight(int height, int64_t tipmediantime, CChainParams chainParams)
+{
+    auto checkpointData = chainParams.Checkpoints();
+    return EstimateNetHeightInner(
+        height, tipmediantime,
+        Checkpoints::GetTotalBlocksEstimate(checkpointData),
+        checkpointData.nTimeLastCheckpoint,
+        chainParams.GenesisBlock().nTime,
+        chainParams.GetConsensus().nPowTargetSpacing);
 }
 
 void TriggerRefresh()
@@ -101,6 +179,11 @@ static bool metrics_ThreadSafeMessageBox(const std::string& message,
     return false;
 }
 
+static bool metrics_ThreadSafeQuestion(const std::string& /* ignored interactive message */, const std::string& message, const std::string& caption, unsigned int style)
+{
+    return metrics_ThreadSafeMessageBox(message, caption, style);
+}
+
 static void metrics_InitMessage(const std::string& message)
 {
     *initMessage = message;
@@ -110,20 +193,46 @@ void ConnectMetricsScreen()
 {
     uiInterface.ThreadSafeMessageBox.disconnect_all_slots();
     uiInterface.ThreadSafeMessageBox.connect(metrics_ThreadSafeMessageBox);
+    uiInterface.ThreadSafeQuestion.disconnect_all_slots();
+    uiInterface.ThreadSafeQuestion.connect(metrics_ThreadSafeQuestion);
     uiInterface.InitMessage.disconnect_all_slots();
     uiInterface.InitMessage.connect(metrics_InitMessage);
 }
 
-int printNetworkStats()
+int printStats(bool mining)
 {
-    LOCK2(cs_main, cs_vNodes);
+    // Number of lines that are always displayed
+    int lines = 4;
+
+    int height;
+    int64_t tipmediantime;
+    size_t connections;
+    int64_t netsolps;
+    {
+        LOCK2(cs_main, cs_vNodes);
+        height = chainActive.Height();
+        tipmediantime = chainActive.LastTip()->GetMedianTimePast();
+        connections = vNodes.size();
+        netsolps = GetNetworkHashPS(120, -1);
+    }
+    auto localsolps = GetLocalSolPS();
 
-    std::cout << "           " << _("Block height") << " | " << chainActive.Height() << std::endl;
-    std::cout << "  " << _("Network solution rate") << " | " << GetNetworkHashPS(120, -1) << " Sol/s" << std::endl;
-    std::cout << "            " << _("Connections") << " | " << vNodes.size() << std::endl;
+    if (IsInitialBlockDownload()) {
+        int netheight = EstimateNetHeight(height, tipmediantime, Params());
+        int downloadPercent = height * 100 / netheight;
+        std::cout << "     " << _("Downloading blocks") << " | " << height << " / ~" << netheight << " (" << downloadPercent << "%)" << std::endl;
+    } else {
+        std::cout << "           " << _("Block height") << " | " << height << std::endl;
+    }
+    std::cout << "            " << _("Connections") << " | " << connections << std::endl;
+    std::cout << "  " << _("Network solution rate") << " | " << netsolps << " Sol/s" << std::endl;
+    if (mining && miningTimer.running()) {
+        std::cout << "    " << _("Local solution rate") << " | " << strprintf("%.4f Sol/s", localsolps) << std::endl;
+        lines++;
+    }
     std::cout << std::endl;
 
-    return 4;
+    return lines;
 }
 
 int printMiningStatus(bool mining)
@@ -133,16 +242,24 @@ 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();
+        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 {
+            bool fvNodesEmpty;
+            {
+                LOCK(cs_vNodes);
+                fvNodesEmpty = vNodes.empty();
+            }
+            if (fvNodesEmpty) {
+                std::cout << _("Mining is paused while waiting for connections.") << std::endl;
+            } else if (IsInitialBlockDownload()) {
+                std::cout << _("Mining is paused while downloading blocks.") << std::endl;
+            } else {
+                std::cout << _("Mining is paused (a JoinSplit may be in progress).") << std::endl;
+            }
         }
-        std::cout << strprintf(_("You are mining with the %s solver on %d threads."),
-                               GetArg("-equihashsolver", "default"), nThreads) << std::endl;
         lines++;
     } else {
         std::cout << _("You are currently not mining.") << std::endl;
@@ -194,11 +311,8 @@ int printMetrics(size_t cols, bool mining)
     }
 
     if (mining && loaded) {
-        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;
-        lines += 2;
+        lines++;
 
         int mined = 0;
         int orphaned = 0;
@@ -264,20 +378,19 @@ int printMessageBox(size_t cols)
     int lines = 2 + u->size();
     std::cout << _("Messages:") << std::endl;
     for (auto it = u->cbegin(); it != u->cend(); ++it) {
-        std::cout << *it << std::endl;
+        auto msg = FormatParagraph(*it, cols, 2);
+        std::cout << "- " << msg << std::endl;
         // Handle newlines and wrapped lines
         size_t i = 0;
         size_t j = 0;
-        while (j < it->size()) {
-            i = it->find('\n', j);
+        while (j < msg.size()) {
+            i = msg.find('\n', j);
             if (i == std::string::npos) {
-                i = it->size();
+                i = msg.size();
             } else {
                 // Newline
                 lines++;
             }
-            // Wrapped lines
-            lines += ((i-j) / cols);
             j = i + 1;
         }
     }
@@ -323,6 +436,9 @@ void ThreadShowMetricsScreen()
         // 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;
+
+        // Privacy notice text
+        std::cout << PrivacyInfo();
         std::cout << std::endl;
     }
 
@@ -333,11 +449,17 @@ void ThreadShowMetricsScreen()
 
         // Get current window size
         if (isTTY) {
-            struct winsize w;
-            w.ws_col = 0;
-            if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1 && w.ws_col != 0) {
-                cols = w.ws_col;
-            }
+#ifdef _WIN32
+          CONSOLE_SCREEN_BUFFER_INFO csbi;
+          GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
+          cols = csbi.srWindow.Right - csbi.srWindow.Left + 1;
+          #else
+          struct winsize w;
+          w.ws_col = 0;
+          if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1 && w.ws_col != 0) {
+            cols = w.ws_col;
+          }
+#endif
         }
 
         if (isScreen) {
@@ -353,9 +475,9 @@ void ThreadShowMetricsScreen()
 #endif
 
         if (loaded) {
-            lines += printNetworkStats();
+            lines += printStats(mining);
+            lines += printMiningStatus(mining);
         }
-        lines += printMiningStatus(mining);
         lines += printMetrics(cols, mining);
         lines += printMessageBox(cols);
         lines += printInitMessage();
This page took 0.031064 seconds and 4 git commands to generate.