Bitcoin Core  27.99.0
P2P Digital Currency
trafficgraphwidget.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2022 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 <interfaces/node.h>
7 #include <qt/clientmodel.h>
8 
9 #include <QPainter>
10 #include <QPainterPath>
11 #include <QColor>
12 #include <QTimer>
13 
14 #include <chrono>
15 #include <cmath>
16 
17 #define DESIRED_SAMPLES 800
18 
19 #define XMARGIN 10
20 #define YMARGIN 10
21 
23  : QWidget(parent),
24  vSamplesIn(),
25  vSamplesOut()
26 {
27  timer = new QTimer(this);
28  connect(timer, &QTimer::timeout, this, &TrafficGraphWidget::updateRates);
29 }
30 
32 {
33  clientModel = model;
34  if(model) {
35  nLastBytesIn = model->node().getTotalBytesRecv();
37  }
38 }
39 
40 std::chrono::minutes TrafficGraphWidget::getGraphRange() const { return m_range; }
41 
42 void TrafficGraphWidget::paintPath(QPainterPath &path, QQueue<float> &samples)
43 {
44  int sampleCount = samples.size();
45  if(sampleCount > 0) {
46  int h = height() - YMARGIN * 2, w = width() - XMARGIN * 2;
47  int x = XMARGIN + w;
48  path.moveTo(x, YMARGIN + h);
49  for(int i = 0; i < sampleCount; ++i) {
50  x = XMARGIN + w - w * i / DESIRED_SAMPLES;
51  int y = YMARGIN + h - (int)(h * samples.at(i) / fMax);
52  path.lineTo(x, y);
53  }
54  path.lineTo(x, YMARGIN + h);
55  }
56 }
57 
58 void TrafficGraphWidget::paintEvent(QPaintEvent *)
59 {
60  QPainter painter(this);
61  painter.fillRect(rect(), Qt::black);
62 
63  if(fMax <= 0.0f) return;
64 
65  QColor axisCol(Qt::gray);
66  int h = height() - YMARGIN * 2;
67  painter.setPen(axisCol);
68  painter.drawLine(XMARGIN, YMARGIN + h, width() - XMARGIN, YMARGIN + h);
69 
70  // decide what order of magnitude we are
71  int base = std::floor(std::log10(fMax));
72  float val = std::pow(10.0f, base);
73 
74  const QString units = tr("kB/s");
75  const float yMarginText = 2.0;
76 
77  // draw lines
78  painter.setPen(axisCol);
79  painter.drawText(XMARGIN, YMARGIN + h - h * val / fMax-yMarginText, QString("%1 %2").arg(val).arg(units));
80  for(float y = val; y < fMax; y += val) {
81  int yy = YMARGIN + h - h * y / fMax;
82  painter.drawLine(XMARGIN, yy, width() - XMARGIN, yy);
83  }
84  // if we drew 3 or fewer lines, break them up at the next lower order of magnitude
85  if(fMax / val <= 3.0f) {
86  axisCol = axisCol.darker();
87  val = pow(10.0f, base - 1);
88  painter.setPen(axisCol);
89  painter.drawText(XMARGIN, YMARGIN + h - h * val / fMax-yMarginText, QString("%1 %2").arg(val).arg(units));
90  int count = 1;
91  for(float y = val; y < fMax; y += val, count++) {
92  // don't overwrite lines drawn above
93  if(count % 10 == 0)
94  continue;
95  int yy = YMARGIN + h - h * y / fMax;
96  painter.drawLine(XMARGIN, yy, width() - XMARGIN, yy);
97  }
98  }
99 
100  painter.setRenderHint(QPainter::Antialiasing);
101  if(!vSamplesIn.empty()) {
102  QPainterPath p;
103  paintPath(p, vSamplesIn);
104  painter.fillPath(p, QColor(0, 255, 0, 128));
105  painter.setPen(Qt::green);
106  painter.drawPath(p);
107  }
108  if(!vSamplesOut.empty()) {
109  QPainterPath p;
111  painter.fillPath(p, QColor(255, 0, 0, 128));
112  painter.setPen(Qt::red);
113  painter.drawPath(p);
114  }
115 }
116 
118 {
119  if(!clientModel) return;
120 
121  quint64 bytesIn = clientModel->node().getTotalBytesRecv(),
122  bytesOut = clientModel->node().getTotalBytesSent();
123  float in_rate_kilobytes_per_sec = static_cast<float>(bytesIn - nLastBytesIn) / timer->interval();
124  float out_rate_kilobytes_per_sec = static_cast<float>(bytesOut - nLastBytesOut) / timer->interval();
125  vSamplesIn.push_front(in_rate_kilobytes_per_sec);
126  vSamplesOut.push_front(out_rate_kilobytes_per_sec);
127  nLastBytesIn = bytesIn;
128  nLastBytesOut = bytesOut;
129 
130  while(vSamplesIn.size() > DESIRED_SAMPLES) {
131  vSamplesIn.pop_back();
132  }
133  while(vSamplesOut.size() > DESIRED_SAMPLES) {
134  vSamplesOut.pop_back();
135  }
136 
137  float tmax = 0.0f;
138  for (const float f : vSamplesIn) {
139  if(f > tmax) tmax = f;
140  }
141  for (const float f : vSamplesOut) {
142  if(f > tmax) tmax = f;
143  }
144  fMax = tmax;
145  update();
146 }
147 
148 void TrafficGraphWidget::setGraphRange(std::chrono::minutes new_range)
149 {
150  m_range = new_range;
151  const auto msecs_per_sample{std::chrono::duration_cast<std::chrono::milliseconds>(m_range) / DESIRED_SAMPLES};
152  timer->stop();
153  timer->setInterval(msecs_per_sample);
154 
155  clear();
156 }
157 
159 {
160  timer->stop();
161 
162  vSamplesOut.clear();
163  vSamplesIn.clear();
164  fMax = 0.0f;
165 
166  if(clientModel) {
169  }
170  timer->start();
171 }
Model for Bitcoin network client.
Definition: clientmodel.h:54
interfaces::Node & node() const
Definition: clientmodel.h:63
std::chrono::minutes m_range
void paintEvent(QPaintEvent *) override
ClientModel * clientModel
TrafficGraphWidget(QWidget *parent=nullptr)
std::chrono::minutes getGraphRange() const
void setClientModel(ClientModel *model)
QQueue< float > vSamplesOut
void paintPath(QPainterPath &path, QQueue< float > &samples)
void setGraphRange(std::chrono::minutes new_range)
QQueue< float > vSamplesIn
virtual int64_t getTotalBytesRecv()=0
Get total bytes recv.
virtual int64_t getTotalBytesSent()=0
Get total bytes sent.
static int count
#define YMARGIN
#define XMARGIN
#define DESIRED_SAMPLES