mirror of
https://github.com/d47081/qBittorrent.git
synced 2025-01-27 06:54:20 +00:00
Merge pull request #9600 from dzmat/averager
Rewrite averaging code and reduce horizontal graphs resolution
This commit is contained in:
commit
7befc79081
@ -33,15 +33,67 @@
|
||||
#include "base/global.h"
|
||||
#include "base/utils/misc.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
enum PeriodInSeconds
|
||||
{
|
||||
MIN1_SEC = 60,
|
||||
MIN5_SEC = 5 * 60,
|
||||
MIN30_SEC = 30 * 60,
|
||||
HOUR6_SEC = 6 * 60 * 60
|
||||
};
|
||||
|
||||
const int MIN5_BUF_SIZE = 5 * 60;
|
||||
const int MIN30_BUF_SIZE = 5 * 60;
|
||||
const int HOUR6_BUF_SIZE = 5 * 60;
|
||||
const int DIVIDER_30MIN = MIN30_SEC / MIN30_BUF_SIZE;
|
||||
const int DIVIDER_6HOUR = HOUR6_SEC / HOUR6_BUF_SIZE;
|
||||
}
|
||||
|
||||
SpeedPlotView::Averager::Averager(int divider, boost::circular_buffer<PointData> &sink)
|
||||
: m_divider(divider)
|
||||
, m_sink(sink)
|
||||
, m_counter(0)
|
||||
, m_accumulator {}
|
||||
{
|
||||
}
|
||||
|
||||
void SpeedPlotView::Averager::push(const PointData &pointData)
|
||||
{
|
||||
// Accumulator overflow will be hit in worst case on longest used averaging span,
|
||||
// defined by divider value. Maximum divider is DIVIDER_6HOUR = 72
|
||||
// Using int32 for accumulator we get overflow when transfer speed reaches 2^31/72 ~~ 28.4 MBytes/s.
|
||||
// With quint64 this speed limit is 2^64/72 ~~ 228 PBytes/s.
|
||||
// This speed is inaccessible to an ordinary user.
|
||||
m_accumulator.x += pointData.x;
|
||||
for (int id = UP; id < NB_GRAPHS; ++id)
|
||||
m_accumulator.y[id] += pointData.y[id];
|
||||
m_counter = (m_counter + 1) % m_divider;
|
||||
if (m_counter != 0)
|
||||
return; // still accumulating
|
||||
// it is time final averaging calculations
|
||||
for (int id = UP; id < NB_GRAPHS; ++id)
|
||||
m_accumulator.y[id] /= m_divider;
|
||||
m_accumulator.x /= m_divider;
|
||||
// now flush out averaged data
|
||||
m_sink.push_back(m_accumulator);
|
||||
m_accumulator = {};
|
||||
}
|
||||
|
||||
bool SpeedPlotView::Averager::isReady() const
|
||||
{
|
||||
return m_counter == 0;
|
||||
}
|
||||
|
||||
SpeedPlotView::SpeedPlotView(QWidget *parent)
|
||||
: QGraphicsView(parent)
|
||||
, m_data5Min(MIN5_BUF_SIZE)
|
||||
, m_data30Min(MIN30_BUF_SIZE)
|
||||
, m_data6Hour(HOUR6_BUF_SIZE)
|
||||
, m_averager30Min(DIVIDER_30MIN, m_data30Min)
|
||||
, m_averager6Hour(DIVIDER_6HOUR, m_data6Hour)
|
||||
, m_period(MIN5)
|
||||
, m_viewablePointsCount(MIN5_SEC)
|
||||
, m_counter30Min(-1)
|
||||
, m_counter6Hour(-1)
|
||||
{
|
||||
QPen greenPen;
|
||||
greenPen.setWidthF(1.5);
|
||||
@ -80,30 +132,11 @@ void SpeedPlotView::setGraphEnable(GraphID id, bool enable)
|
||||
viewport()->update();
|
||||
}
|
||||
|
||||
void SpeedPlotView::pushPoint(SpeedPlotView::PointData point)
|
||||
void SpeedPlotView::pushPoint(const SpeedPlotView::PointData &point)
|
||||
{
|
||||
m_counter30Min = (m_counter30Min + 1) % 3;
|
||||
m_counter6Hour = (m_counter6Hour + 1) % 18;
|
||||
|
||||
m_data5Min.push_back(point);
|
||||
|
||||
if (m_counter30Min == 0) {
|
||||
m_data30Min.push_back(point);
|
||||
}
|
||||
else {
|
||||
m_data30Min.back().x = (m_data30Min.back().x * m_counter30Min + point.x) / (m_counter30Min + 1);
|
||||
for (int id = UP; id < NB_GRAPHS; ++id)
|
||||
m_data30Min.back().y[id] = (m_data30Min.back().y[id] * m_counter30Min + point.y[id]) / (m_counter30Min + 1);
|
||||
}
|
||||
|
||||
if (m_counter6Hour == 0) {
|
||||
m_data6Hour.push_back(point);
|
||||
}
|
||||
else {
|
||||
m_data6Hour.back().x = (m_data6Hour.back().x * m_counter6Hour + point.x) / (m_counter6Hour + 1);
|
||||
for (int id = UP; id < NB_GRAPHS; ++id)
|
||||
m_data6Hour.back().y[id] = (m_data6Hour.back().y[id] * m_counter6Hour + point.y[id]) / (m_counter6Hour + 1);
|
||||
}
|
||||
m_averager30Min.push(point);
|
||||
m_averager6Hour.push(point);
|
||||
}
|
||||
|
||||
void SpeedPlotView::setViewableLastPoints(TimePeriod period)
|
||||
@ -132,8 +165,8 @@ void SpeedPlotView::replot()
|
||||
{
|
||||
if ((m_period == MIN1)
|
||||
|| (m_period == MIN5)
|
||||
|| ((m_period == MIN30) && (m_counter30Min == 2))
|
||||
|| ((m_period == HOUR6) && (m_counter6Hour == 17)))
|
||||
|| ((m_period == MIN30) && m_averager30Min.isReady())
|
||||
|| ((m_period == HOUR6) && m_averager6Hour.isReady()) )
|
||||
viewport()->update();
|
||||
}
|
||||
|
||||
@ -151,11 +184,11 @@ boost::circular_buffer<SpeedPlotView::PointData> &SpeedPlotView::getCurrentData(
|
||||
}
|
||||
}
|
||||
|
||||
int SpeedPlotView::maxYValue()
|
||||
quint64 SpeedPlotView::maxYValue()
|
||||
{
|
||||
boost::circular_buffer<PointData> &queue = getCurrentData();
|
||||
|
||||
int maxYValue = 0;
|
||||
quint64 maxYValue = 0;
|
||||
for (int id = UP; id < NB_GRAPHS; ++id) {
|
||||
|
||||
if (!m_properties[static_cast<GraphID>(id)].enable)
|
||||
@ -179,7 +212,7 @@ void SpeedPlotView::paintEvent(QPaintEvent *)
|
||||
|
||||
rect.adjust(4, 4, 0, -4); // Add padding
|
||||
|
||||
int maxY = maxYValue();
|
||||
quint64 maxY = maxYValue();
|
||||
|
||||
rect.adjust(0, fontMetrics.height(), 0, 0); // Add top padding for top speed text
|
||||
|
||||
@ -263,7 +296,7 @@ void SpeedPlotView::paintEvent(QPaintEvent *)
|
||||
continue;
|
||||
|
||||
if (fontMetrics.width(property.name) > legendWidth)
|
||||
legendWidth = fontMetrics.width(property.name);
|
||||
legendWidth = fontMetrics.width(property.name);
|
||||
legendHeight += 1.5 * fontMetrics.height();
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,7 @@ public:
|
||||
struct PointData
|
||||
{
|
||||
qint64 x;
|
||||
int y[NB_GRAPHS];
|
||||
quint64 y[NB_GRAPHS];
|
||||
};
|
||||
|
||||
explicit SpeedPlotView(QWidget *parent = nullptr);
|
||||
@ -78,7 +78,7 @@ public:
|
||||
void setGraphEnable(GraphID id, bool enable);
|
||||
void setViewableLastPoints(TimePeriod period);
|
||||
|
||||
void pushPoint(PointData point);
|
||||
void pushPoint(const PointData &point);
|
||||
|
||||
void replot();
|
||||
|
||||
@ -86,19 +86,18 @@ protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
enum PeriodInSeconds
|
||||
class Averager
|
||||
{
|
||||
MIN1_SEC = 60,
|
||||
MIN5_SEC = 5 * 60,
|
||||
MIN30_SEC = 30 * 60,
|
||||
HOUR6_SEC = 6 * 60 * 60
|
||||
};
|
||||
public:
|
||||
Averager(int divider, boost::circular_buffer<PointData> &sink);
|
||||
void push(const PointData &pointData);
|
||||
bool isReady() const;
|
||||
|
||||
enum PointsToSave
|
||||
{
|
||||
MIN5_BUF_SIZE = 5 * 60,
|
||||
MIN30_BUF_SIZE = 10 * 60,
|
||||
HOUR6_BUF_SIZE = 20 * 60
|
||||
private:
|
||||
const int m_divider;
|
||||
boost::circular_buffer<PointData> &m_sink;
|
||||
int m_counter;
|
||||
PointData m_accumulator;
|
||||
};
|
||||
|
||||
struct GraphProperties
|
||||
@ -111,19 +110,19 @@ private:
|
||||
bool enable;
|
||||
};
|
||||
|
||||
int maxYValue();
|
||||
quint64 maxYValue();
|
||||
boost::circular_buffer<PointData> &getCurrentData();
|
||||
|
||||
boost::circular_buffer<PointData> m_data5Min;
|
||||
boost::circular_buffer<PointData> m_data30Min;
|
||||
boost::circular_buffer<PointData> m_data6Hour;
|
||||
Averager m_averager30Min;
|
||||
Averager m_averager6Hour;
|
||||
|
||||
QMap<GraphID, GraphProperties> m_properties;
|
||||
|
||||
TimePeriod m_period;
|
||||
int m_viewablePointsCount;
|
||||
|
||||
int m_counter30Min;
|
||||
int m_counter6Hour;
|
||||
};
|
||||
|
||||
#endif // SPEEDPLOTVIEW_H
|
||||
|
Loading…
x
Reference in New Issue
Block a user