Skip to content
Bitcoin Roots

v29.4-roots.1 · Commit 2: [PATCH 02/13] runtime: preserve shared operator controls

src/stats/stats.cpp

Before: /dev/null · After: src/stats/stats.cpp

File metadata
new file mode 100644
index 0000000000000000000000000000000000000000..b496d4b6a20b8cd48f5a0cf855c4d9b2821665de

Download original patch · Release notes

Diff rows 1–132 of 132. Line numbers refer to the original before/after files.

+ Added− RemovedUnmarked lines are context.

Scroll the code area horizontally to read long lines. The two line-number columns refer to before and after.

src/stats/stats.cpp ADDED
@@ -0,0 +1,132 @@
1
+ // Copyright (c) 2016 The Bitcoin Core 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 <stats/stats.h>
6
+
7
+ #include <memusage.h>
8
+ #include <util/time.h>
9
+
10
+ #include <cmath>
11
+
12
+ static const uint32_t SAMPLE_MIN_DELTA_IN_SEC = 2;
13
+ static const int CLEANUP_SAMPLES_THRESHOLD = 100;
14
+ size_t CStats::maxStatsMemory = 0;
15
+ const size_t CStats::DEFAULT_MAX_STATS_MEMORY = 10 * 1024 * 1024; //10 MB
16
+
17
+ // NOTE: stats/init.cpp help for -statsenable needs to be manually updated
18
+ const bool CStats::DEFAULT_STATISTICS_ENABLED = false;
19
+
20
+ std::atomic<bool> CStats::m_stats_enabled(false); //disable stats by default
21
+
22
+ CStats* CStats::m_shared_instance{nullptr};
23
+
24
+ CStats* CStats::DefaultStats()
25
+ {
26
+ if (!m_shared_instance)
27
+ m_shared_instance = new CStats();
28
+
29
+ return m_shared_instance;
30
+ }
31
+
32
+ void CStats::addMempoolSample(int64_t txcount, int64_t dynUsage, int64_t currentMinRelayFee)
33
+ {
34
+ if (!m_stats_enabled)
35
+ return;
36
+
37
+ uint64_t now = GetTime();
38
+ {
39
+ LOCK(cs_stats);
40
+
41
+ // set the mempool stats start time if this is the first sample
42
+ if (m_mempool_stats.m_start_time == 0)
43
+ m_mempool_stats.m_start_time = now;
44
+
45
+ // ensure the minimum time delta between samples
46
+ if (m_mempool_stats.m_samples.size() && m_mempool_stats.m_start_time + m_mempool_stats.m_samples.back().m_time_delta + SAMPLE_MIN_DELTA_IN_SEC >= now) {
47
+ return;
48
+ }
49
+
50
+ // calculate the current time delta and add a sample
51
+ uint32_t timeDelta = now - m_mempool_stats.m_start_time; //truncate to uint32_t should be sufficient
52
+ m_mempool_stats.m_samples.push_back({timeDelta, txcount, dynUsage, currentMinRelayFee});
53
+ m_mempool_stats.m_cleanup_counter++;
54
+
55
+ // check if we should cleanup the container
56
+ if (m_mempool_stats.m_cleanup_counter >= CLEANUP_SAMPLES_THRESHOLD) {
57
+ //check memory usage
58
+ if (memusage::DynamicUsage(m_mempool_stats.m_samples) > maxStatsMemory && m_mempool_stats.m_samples.size() > 1) {
59
+ // only shrink if the vector.capacity() is > the target for performance reasons
60
+ m_mempool_stats.m_samples.shrink_to_fit();
61
+ const size_t memUsage = memusage::DynamicUsage(m_mempool_stats.m_samples);
62
+ // calculate the amount of samples we need to remove
63
+ size_t itemsToRemove = (memUsage - maxStatsMemory + sizeof(m_mempool_stats.m_samples[0]) - 1) / sizeof(m_mempool_stats.m_samples[0]);
64
+
65
+ // sanity check; always keep the most recent sample we just added
66
+ if (m_mempool_stats.m_samples.size() <= itemsToRemove) {
67
+ itemsToRemove = m_mempool_stats.m_samples.size() - 1;
68
+ }
69
+ m_mempool_stats.m_samples.erase(m_mempool_stats.m_samples.begin(), m_mempool_stats.m_samples.begin() + itemsToRemove);
70
+ }
71
+ // shrink vector
72
+ m_mempool_stats.m_samples.shrink_to_fit();
73
+ m_mempool_stats.m_cleanup_counter = 0;
74
+ }
75
+
76
+ // fire signal
77
+ MempoolStatsDidChange();
78
+ }
79
+ }
80
+
81
+ mempoolSamples_t CStats::mempoolGetValuesInRange(uint64_t& fromTime, uint64_t& toTime)
82
+ {
83
+ if (!m_stats_enabled)
84
+ return mempoolSamples_t();
85
+
86
+ LOCK(cs_stats);
87
+
88
+ // if empty, return directly
89
+ if (!m_mempool_stats.m_samples.size())
90
+ return m_mempool_stats.m_samples;
91
+
92
+
93
+ if (!(fromTime == 0 && toTime == 0) && (fromTime > m_mempool_stats.m_start_time + m_mempool_stats.m_samples.front().m_time_delta || toTime < m_mempool_stats.m_start_time + m_mempool_stats.m_samples.back().m_time_delta)) {
94
+ mempoolSamples_t::iterator fromSample = m_mempool_stats.m_samples.begin();
95
+ mempoolSamples_t::iterator toSample = std::prev(m_mempool_stats.m_samples.end());
96
+
97
+ // create subset of samples
98
+ bool fromSet = false;
99
+ for (mempoolSamples_t::iterator it = m_mempool_stats.m_samples.begin(); it != m_mempool_stats.m_samples.end(); ++it) {
100
+ if (m_mempool_stats.m_start_time + (*it).m_time_delta >= fromTime && !fromSet) {
101
+ fromSample = it;
102
+ fromSet = true;
103
+ }
104
+ else if (m_mempool_stats.m_start_time + (*it).m_time_delta > toTime) {
105
+ toSample = std::prev(it);
106
+ break;
107
+ }
108
+ }
109
+
110
+ mempoolSamples_t subset(fromSample, toSample + 1);
111
+
112
+ // set the fromTime and toTime pass-by-ref parameters
113
+ fromTime = m_mempool_stats.m_start_time + (*fromSample).m_time_delta;
114
+ toTime = m_mempool_stats.m_start_time + (*toSample).m_time_delta;
115
+
116
+ // return subset
117
+ return subset;
118
+ }
119
+
120
+ // return all available samples
121
+ fromTime = m_mempool_stats.m_start_time + m_mempool_stats.m_samples.front().m_time_delta;
122
+ toTime = m_mempool_stats.m_start_time + m_mempool_stats.m_samples.back().m_time_delta;
123
+ return m_mempool_stats.m_samples;
124
+ }
125
+
126
+ void CStats::setMaxMemoryUsageTarget(size_t maxMem)
127
+ {
128
+ m_stats_enabled = (maxMem > 0);
129
+
130
+ LOCK(cs_stats);
131
+ maxStatsMemory = maxMem;
132
+ }