]> Git Repo - VerusCoin.git/blob - src/metrics.cpp
All latest updates, smart contracts, including oracle from KMD/jl777
[VerusCoin.git] / src / metrics.cpp
1 // Copyright (c) 2016 The Zcash developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 #include "metrics.h"
6
7 #include "chainparams.h"
8 #include "checkpoints.h"
9 #include "main.h"
10 #include "ui_interface.h"
11 #include "util.h"
12 #include "utiltime.h"
13 #include "utilmoneystr.h"
14 #include "utilstrencodings.h"
15
16 #include <boost/thread.hpp>
17 #include <boost/thread/synchronized_value.hpp>
18 #include <string>
19 #ifdef _WIN32
20 #include <io.h>
21 #include <windows.h>
22 #else
23 #include <sys/ioctl.h>
24 #endif
25 #include <unistd.h>
26
27 extern int64_t ASSETCHAINS_TIMELOCKGTE;
28 extern uint32_t ASSETCHAINS_ALGO, ASSETCHAINS_VERUSHASH;
29 int64_t komodo_block_unlocktime(uint32_t nHeight);
30
31 void AtomicTimer::start()
32 {
33     std::unique_lock<std::mutex> lock(mtx);
34     if (threads < 1) {
35         start_time = GetTime();
36     }
37     ++threads;
38 }
39
40 void AtomicTimer::stop()
41 {
42     std::unique_lock<std::mutex> lock(mtx);
43     // Ignore excess calls to stop()
44     if (threads > 0) {
45         --threads;
46         if (threads < 1) {
47             int64_t time_span = GetTime() - start_time;
48             total_time += time_span;
49         }
50     }
51 }
52
53 bool AtomicTimer::running()
54 {
55     std::unique_lock<std::mutex> lock(mtx);
56     return threads > 0;
57 }
58
59 uint64_t AtomicTimer::threadCount()
60 {
61     std::unique_lock<std::mutex> lock(mtx);
62     return threads;
63 }
64
65 double AtomicTimer::rate(const AtomicCounter& count)
66 {
67     std::unique_lock<std::mutex> lock(mtx);
68     int64_t duration = total_time;
69     if (threads > 0) {
70         // Timer is running, so get the latest count
71         duration += GetTime() - start_time;
72     }
73     return duration > 0 ? (double)count.get() / duration : 0;
74 }
75
76 CCriticalSection cs_metrics;
77
78 double AtomicTimer::rate(const int64_t count)
79 {
80     std::unique_lock<std::mutex> lock(mtx);
81     LOCK(cs_metrics);
82     int64_t duration = total_time;
83     if (threads > 0) {
84         // Timer is running, so get the latest count
85         duration += GetTime() - start_time;
86     }
87     return duration > 0 ? (double)count / duration : 0;
88 }
89
90 boost::synchronized_value<int64_t> nNodeStartTime;
91 boost::synchronized_value<int64_t> nNextRefresh;
92 int64_t nHashCount;
93 AtomicCounter transactionsValidated;
94 AtomicCounter ehSolverRuns;
95 AtomicCounter solutionTargetChecks;
96 AtomicCounter minedBlocks;
97 AtomicTimer miningTimer;
98
99 boost::synchronized_value<std::list<uint256>> trackedBlocks;
100
101 boost::synchronized_value<std::list<std::string>> messageBox;
102 boost::synchronized_value<std::string> initMessage;
103 bool loaded = false;
104
105 extern int64_t GetNetworkHashPS(int lookup, int height);
106
107 void TrackMinedBlock(uint256 hash)
108 {
109     LOCK(cs_metrics);
110     minedBlocks.increment();
111     trackedBlocks->push_back(hash);
112 }
113
114 void MarkStartTime()
115 {
116     *nNodeStartTime = GetTime();
117 }
118
119 int64_t GetUptime()
120 {
121     return GetTime() - *nNodeStartTime;
122 }
123
124 double GetLocalSolPS()
125 {
126     if (ASSETCHAINS_ALGO == ASSETCHAINS_VERUSHASH)
127     {
128         return miningTimer.rate(nHashCount);
129     }
130     else
131         return miningTimer.rate(solutionTargetChecks);
132 }
133
134 int EstimateNetHeightInner(int height, int64_t tipmediantime,
135                            int heightLastCheckpoint, int64_t timeLastCheckpoint,
136                            int64_t genesisTime, int64_t targetSpacing)
137 {
138     // We average the target spacing with the observed spacing to the last
139     // checkpoint (either from below or above depending on the current height),
140     // and use that to estimate the current network height.
141     int medianHeight = height > CBlockIndex::nMedianTimeSpan ?
142             height - (1 + ((CBlockIndex::nMedianTimeSpan - 1) / 2)) :
143             height / 2;
144     double checkpointSpacing = medianHeight > heightLastCheckpoint ?
145             (double (tipmediantime - timeLastCheckpoint)) / (medianHeight - heightLastCheckpoint) :
146             (double (timeLastCheckpoint - genesisTime)) / heightLastCheckpoint;
147     double averageSpacing = (targetSpacing + checkpointSpacing) / 2;
148     int netheight = medianHeight + ((GetTime() - tipmediantime) / averageSpacing);
149     // Round to nearest ten to reduce noise
150     return ((netheight + 5) / 10) * 10;
151 }
152
153 int EstimateNetHeight(int height, int64_t tipmediantime, CChainParams chainParams)
154 {
155     auto checkpointData = chainParams.Checkpoints();
156     return EstimateNetHeightInner(
157         height, tipmediantime,
158         Checkpoints::GetTotalBlocksEstimate(checkpointData),
159         checkpointData.nTimeLastCheckpoint,
160         chainParams.GenesisBlock().nTime,
161         chainParams.GetConsensus().nPowTargetSpacing);
162 }
163
164 void TriggerRefresh()
165 {
166     *nNextRefresh = GetTime();
167     // Ensure that the refresh has started before we return
168     MilliSleep(200);
169 }
170
171 static bool metrics_ThreadSafeMessageBox(const std::string& message,
172                                       const std::string& caption,
173                                       unsigned int style)
174 {
175     // The SECURE flag has no effect in the metrics UI.
176     style &= ~CClientUIInterface::SECURE;
177
178     std::string strCaption;
179     // Check for usage of predefined caption
180     switch (style) {
181     case CClientUIInterface::MSG_ERROR:
182         strCaption += _("Error");
183         break;
184     case CClientUIInterface::MSG_WARNING:
185         strCaption += _("Warning");
186         break;
187     case CClientUIInterface::MSG_INFORMATION:
188         strCaption += _("Information");
189         break;
190     default:
191         strCaption += caption; // Use supplied caption (can be empty)
192     }
193
194     boost::strict_lock_ptr<std::list<std::string>> u = messageBox.synchronize();
195     u->push_back(strCaption + ": " + message);
196     if (u->size() > 5) {
197         u->pop_back();
198     }
199
200     TriggerRefresh();
201     return false;
202 }
203
204 static bool metrics_ThreadSafeQuestion(const std::string& /* ignored interactive message */, const std::string& message, const std::string& caption, unsigned int style)
205 {
206     return metrics_ThreadSafeMessageBox(message, caption, style);
207 }
208
209 static void metrics_InitMessage(const std::string& message)
210 {
211     *initMessage = message;
212 }
213
214 void ConnectMetricsScreen()
215 {
216     uiInterface.ThreadSafeMessageBox.disconnect_all_slots();
217     uiInterface.ThreadSafeMessageBox.connect(metrics_ThreadSafeMessageBox);
218     uiInterface.ThreadSafeQuestion.disconnect_all_slots();
219     uiInterface.ThreadSafeQuestion.connect(metrics_ThreadSafeQuestion);
220     uiInterface.InitMessage.disconnect_all_slots();
221     uiInterface.InitMessage.connect(metrics_InitMessage);
222 }
223
224 int printStats(bool mining)
225 {
226     // Number of lines that are always displayed
227     int lines = 4;
228
229     int height;
230     int64_t tipmediantime;
231     size_t connections;
232     int64_t netsolps;
233     {
234         LOCK2(cs_main, cs_vNodes);
235         height = chainActive.Height();
236         tipmediantime = chainActive.LastTip()->GetMedianTimePast();
237         connections = vNodes.size();
238         netsolps = GetNetworkHashPS(120, -1);
239     }
240     auto localsolps = GetLocalSolPS();
241
242     if (IsInitialBlockDownload()) {
243         int netheight = EstimateNetHeight(height, tipmediantime, Params());
244         int downloadPercent = height * 100 / netheight;
245         std::cout << "     " << _("Downloading blocks") << " | " << height << " / ~" << netheight << " (" << downloadPercent << "%)" << std::endl;
246     } else {
247         std::cout << "           " << _("Block height") << " | " << height << std::endl;
248     }
249     std::cout << "            " << _("Connections") << " | " << connections << std::endl;
250     std::cout << "  " << _("Network solution rate") << " | " << netsolps << " Sol/s" << std::endl;
251     if (mining && miningTimer.running()) {
252         std::cout << "    " << _("Local solution rate") << " | " << strprintf("%.4f Sol/s", localsolps) << std::endl;
253         lines++;
254     }
255     std::cout << std::endl;
256
257     return lines;
258 }
259
260 int printMiningStatus(bool mining)
261 {
262 #ifdef ENABLE_MINING
263     // Number of lines that are always displayed
264     int lines = 1;
265
266     if (mining) {
267         auto nThreads = miningTimer.threadCount();
268         if (nThreads > 0) {
269             std::cout << strprintf(_("You are mining with the %s solver on %d threads."),
270                                    GetArg("-equihashsolver", "default"), nThreads) << std::endl;
271         } else {
272             bool fvNodesEmpty;
273             {
274                 LOCK(cs_vNodes);
275                 fvNodesEmpty = vNodes.empty();
276             }
277             if (fvNodesEmpty) {
278                 std::cout << _("Mining is paused while waiting for connections.") << std::endl;
279             } else if (IsInitialBlockDownload()) {
280                 std::cout << _("Mining is paused while downloading blocks.") << std::endl;
281             } else {
282                 std::cout << _("Mining is paused (a JoinSplit may be in progress).") << std::endl;
283             }
284         }
285         lines++;
286     } else {
287         std::cout << _("You are currently not mining.") << std::endl;
288         std::cout << _("To enable mining, add 'gen=1' to your zcash.conf and restart.") << std::endl;
289         lines += 2;
290     }
291     std::cout << std::endl;
292
293     return lines;
294 #else // ENABLE_MINING
295     return 0;
296 #endif // !ENABLE_MINING
297 }
298
299 int printMetrics(size_t cols, bool mining)
300 {
301     // Number of lines that are always displayed
302     int lines = 3;
303
304     // Calculate uptime
305     int64_t uptime = GetUptime();
306     int days = uptime / (24 * 60 * 60);
307     int hours = (uptime - (days * 24 * 60 * 60)) / (60 * 60);
308     int minutes = (uptime - (((days * 24) + hours) * 60 * 60)) / 60;
309     int seconds = uptime - (((((days * 24) + hours) * 60) + minutes) * 60);
310
311     // Display uptime
312     std::string duration;
313     if (days > 0) {
314         duration = strprintf(_("%d days, %d hours, %d minutes, %d seconds"), days, hours, minutes, seconds);
315     } else if (hours > 0) {
316         duration = strprintf(_("%d hours, %d minutes, %d seconds"), hours, minutes, seconds);
317     } else if (minutes > 0) {
318         duration = strprintf(_("%d minutes, %d seconds"), minutes, seconds);
319     } else {
320         duration = strprintf(_("%d seconds"), seconds);
321     }
322     std::string strDuration = strprintf(_("Since starting this node %s ago:"), duration);
323     std::cout << strDuration << std::endl;
324     lines += (strDuration.size() / cols);
325
326     int validatedCount = transactionsValidated.get();
327     if (validatedCount > 1) {
328       std::cout << "- " << strprintf(_("You have validated %d transactions!"), validatedCount) << std::endl;
329     } else if (validatedCount == 1) {
330       std::cout << "- " << _("You have validated a transaction!") << std::endl;
331     } else {
332       std::cout << "- " << _("You have validated no transactions.") << std::endl;
333     }
334
335     if (mining && loaded) {
336         std::cout << "- " << strprintf(_("You have completed %d Equihash solver runs."), ehSolverRuns.get()) << std::endl;
337         lines++;
338
339         int mined = 0;
340         int orphaned = 0;
341         CAmount immature {0};
342         CAmount mature {0};
343         {
344             LOCK2(cs_main, cs_metrics);
345             boost::strict_lock_ptr<std::list<uint256>> u = trackedBlocks.synchronize();
346             auto consensusParams = Params().GetConsensus();
347             auto tipHeight = chainActive.Height();
348
349             // Update orphans and calculate subsidies
350             std::list<uint256>::iterator it = u->begin();
351             while (it != u->end()) {
352                 auto hash = *it;
353                 if (mapBlockIndex.count(hash) > 0 &&
354                         chainActive.Contains(mapBlockIndex[hash])) {
355                     int height = mapBlockIndex[hash]->nHeight;
356                     CAmount subsidy = GetBlockSubsidy(height, consensusParams);
357                     if ((height > 0) && (height <= consensusParams.GetLastFoundersRewardBlockHeight())) {
358                         subsidy -= subsidy/5;
359                     }
360
361                     if ((std::max(0, COINBASE_MATURITY - (tipHeight - height)) > 0) ||
362                         (tipHeight < komodo_block_unlocktime(height) && subsidy >= ASSETCHAINS_TIMELOCKGTE)) {
363                         immature += subsidy;
364                     } else {
365                         mature += subsidy;
366                     }
367                     it++;
368                 } else {
369                     it = u->erase(it);
370                 }
371             }
372
373             mined = minedBlocks.get();
374             orphaned = mined - u->size();
375         }
376
377         if (mined > 0) {
378             std::string units = Params().CurrencyUnits();
379             std::cout << "- " << strprintf(_("You have mined %d blocks!"), mined) << std::endl;
380             std::cout << "  "
381                       << strprintf(_("Orphaned: %d blocks, Immature: %u %s, Mature: %u %s"),
382                                      orphaned,
383                                      FormatMoney(immature), units,
384                                      FormatMoney(mature), units)
385                       << std::endl;
386             lines += 2;
387         }
388     }
389     std::cout << std::endl;
390
391     return lines;
392 }
393
394 int printMessageBox(size_t cols)
395 {
396     boost::strict_lock_ptr<std::list<std::string>> u = messageBox.synchronize();
397
398     if (u->size() == 0) {
399         return 0;
400     }
401
402     int lines = 2 + u->size();
403     std::cout << _("Messages:") << std::endl;
404     for (auto it = u->cbegin(); it != u->cend(); ++it) {
405         auto msg = FormatParagraph(*it, cols, 2);
406         std::cout << "- " << msg << std::endl;
407         // Handle newlines and wrapped lines
408         size_t i = 0;
409         size_t j = 0;
410         while (j < msg.size()) {
411             i = msg.find('\n', j);
412             if (i == std::string::npos) {
413                 i = msg.size();
414             } else {
415                 // Newline
416                 lines++;
417             }
418             j = i + 1;
419         }
420     }
421     std::cout << std::endl;
422     return lines;
423 }
424
425 int printInitMessage()
426 {
427     if (loaded) {
428         return 0;
429     }
430
431     std::string msg = *initMessage;
432     std::cout << _("Init message:") << " " << msg << std::endl;
433     std::cout << std::endl;
434
435     if (msg == _("Done loading")) {
436         loaded = true;
437     }
438
439     return 2;
440 }
441
442 void ThreadShowMetricsScreen()
443 {
444     // Make this thread recognisable as the metrics screen thread
445     RenameThread("zcash-metrics-screen");
446
447     // Determine whether we should render a persistent UI or rolling metrics
448     bool isTTY = isatty(STDOUT_FILENO);
449     bool isScreen = GetBoolArg("-metricsui", isTTY);
450     int64_t nRefresh = GetArg("-metricsrefreshtime", isTTY ? 1 : 600);
451
452     if (isScreen) {
453         // Clear screen
454         std::cout << "\e[2J";
455
456         // Print art
457         std::cout << METRICS_ART << std::endl;
458         std::cout << std::endl;
459
460         // Thank you text
461         std::cout << _("Thank you for running a Zcash node!") << std::endl;
462         std::cout << _("You're helping to strengthen the network and contributing to a social good :)") << std::endl;
463
464         // Privacy notice text
465         std::cout << PrivacyInfo();
466         std::cout << std::endl;
467     }
468
469     while (true) {
470         // Number of lines that are always displayed
471         int lines = 1;
472         int cols = 80;
473
474         // Get current window size
475         if (isTTY) {
476 #ifdef _WIN32
477           CONSOLE_SCREEN_BUFFER_INFO csbi;
478           GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
479           cols = csbi.srWindow.Right - csbi.srWindow.Left + 1;
480           #else
481           struct winsize w;
482           w.ws_col = 0;
483           if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1 && w.ws_col != 0) {
484             cols = w.ws_col;
485           }
486 #endif
487         }
488
489         if (isScreen) {
490             // Erase below current position
491             std::cout << "\e[J";
492         }
493
494         // Miner status
495 #ifdef ENABLE_MINING
496         bool mining = GetBoolArg("-gen", false);
497 #else
498         bool mining = false;
499 #endif
500
501         if (loaded) {
502             lines += printStats(mining);
503             lines += printMiningStatus(mining);
504         }
505         lines += printMetrics(cols, mining);
506         lines += printMessageBox(cols);
507         lines += printInitMessage();
508
509         if (isScreen) {
510             // Explain how to exit
511             std::cout << "[" << _("Press Ctrl+C to exit") << "] [" << _("Set 'showmetrics=0' to hide") << "]" << std::endl;
512         } else {
513             // Print delineator
514             std::cout << "----------------------------------------" << std::endl;
515         }
516
517         *nNextRefresh = GetTime() + nRefresh;
518         while (GetTime() < *nNextRefresh) {
519             boost::this_thread::interruption_point();
520             MilliSleep(200);
521         }
522
523         if (isScreen) {
524             // Return to the top of the updating section
525             std::cout << "\e[" << lines << "A";
526         }
527     }
528 }
This page took 0.059062 seconds and 4 git commands to generate.