Browse Source

Merge pull request #9600 from dzmat/averager

Rewrite averaging code and reduce horizontal graphs resolution
adaptive-webui-19844
Vladimir Golovnev 6 years ago committed by GitHub
parent
commit
7befc79081
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 91
      src/gui/properties/speedplotview.cpp
  2. 35
      src/gui/properties/speedplotview.h

91
src/gui/properties/speedplotview.cpp

@ -33,15 +33,67 @@
#include "base/global.h" #include "base/global.h"
#include "base/utils/misc.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) SpeedPlotView::SpeedPlotView(QWidget *parent)
: QGraphicsView(parent) : QGraphicsView(parent)
, m_data5Min(MIN5_BUF_SIZE) , m_data5Min(MIN5_BUF_SIZE)
, m_data30Min(MIN30_BUF_SIZE) , m_data30Min(MIN30_BUF_SIZE)
, m_data6Hour(HOUR6_BUF_SIZE) , m_data6Hour(HOUR6_BUF_SIZE)
, m_averager30Min(DIVIDER_30MIN, m_data30Min)
, m_averager6Hour(DIVIDER_6HOUR, m_data6Hour)
, m_period(MIN5) , m_period(MIN5)
, m_viewablePointsCount(MIN5_SEC) , m_viewablePointsCount(MIN5_SEC)
, m_counter30Min(-1)
, m_counter6Hour(-1)
{ {
QPen greenPen; QPen greenPen;
greenPen.setWidthF(1.5); greenPen.setWidthF(1.5);
@ -80,30 +132,11 @@ void SpeedPlotView::setGraphEnable(GraphID id, bool enable)
viewport()->update(); 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); m_data5Min.push_back(point);
m_averager30Min.push(point);
if (m_counter30Min == 0) { m_averager6Hour.push(point);
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);
}
} }
void SpeedPlotView::setViewableLastPoints(TimePeriod period) void SpeedPlotView::setViewableLastPoints(TimePeriod period)
@ -132,8 +165,8 @@ void SpeedPlotView::replot()
{ {
if ((m_period == MIN1) if ((m_period == MIN1)
|| (m_period == MIN5) || (m_period == MIN5)
|| ((m_period == MIN30) && (m_counter30Min == 2)) || ((m_period == MIN30) && m_averager30Min.isReady())
|| ((m_period == HOUR6) && (m_counter6Hour == 17))) || ((m_period == HOUR6) && m_averager6Hour.isReady()) )
viewport()->update(); 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(); boost::circular_buffer<PointData> &queue = getCurrentData();
int maxYValue = 0; quint64 maxYValue = 0;
for (int id = UP; id < NB_GRAPHS; ++id) { for (int id = UP; id < NB_GRAPHS; ++id) {
if (!m_properties[static_cast<GraphID>(id)].enable) if (!m_properties[static_cast<GraphID>(id)].enable)
@ -179,7 +212,7 @@ void SpeedPlotView::paintEvent(QPaintEvent *)
rect.adjust(4, 4, 0, -4); // Add padding 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 rect.adjust(0, fontMetrics.height(), 0, 0); // Add top padding for top speed text

35
src/gui/properties/speedplotview.h

@ -70,7 +70,7 @@ public:
struct PointData struct PointData
{ {
qint64 x; qint64 x;
int y[NB_GRAPHS]; quint64 y[NB_GRAPHS];
}; };
explicit SpeedPlotView(QWidget *parent = nullptr); explicit SpeedPlotView(QWidget *parent = nullptr);
@ -78,7 +78,7 @@ public:
void setGraphEnable(GraphID id, bool enable); void setGraphEnable(GraphID id, bool enable);
void setViewableLastPoints(TimePeriod period); void setViewableLastPoints(TimePeriod period);
void pushPoint(PointData point); void pushPoint(const PointData &point);
void replot(); void replot();
@ -86,19 +86,18 @@ protected:
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
private: private:
enum PeriodInSeconds class Averager
{ {
MIN1_SEC = 60, public:
MIN5_SEC = 5 * 60, Averager(int divider, boost::circular_buffer<PointData> &sink);
MIN30_SEC = 30 * 60, void push(const PointData &pointData);
HOUR6_SEC = 6 * 60 * 60 bool isReady() const;
};
private:
enum PointsToSave const int m_divider;
{ boost::circular_buffer<PointData> &m_sink;
MIN5_BUF_SIZE = 5 * 60, int m_counter;
MIN30_BUF_SIZE = 10 * 60, PointData m_accumulator;
HOUR6_BUF_SIZE = 20 * 60
}; };
struct GraphProperties struct GraphProperties
@ -111,19 +110,19 @@ private:
bool enable; bool enable;
}; };
int maxYValue(); quint64 maxYValue();
boost::circular_buffer<PointData> &getCurrentData(); boost::circular_buffer<PointData> &getCurrentData();
boost::circular_buffer<PointData> m_data5Min; boost::circular_buffer<PointData> m_data5Min;
boost::circular_buffer<PointData> m_data30Min; boost::circular_buffer<PointData> m_data30Min;
boost::circular_buffer<PointData> m_data6Hour; boost::circular_buffer<PointData> m_data6Hour;
Averager m_averager30Min;
Averager m_averager6Hour;
QMap<GraphID, GraphProperties> m_properties; QMap<GraphID, GraphProperties> m_properties;
TimePeriod m_period; TimePeriod m_period;
int m_viewablePointsCount; int m_viewablePointsCount;
int m_counter30Min;
int m_counter6Hour;
}; };
#endif // SPEEDPLOTVIEW_H #endif // SPEEDPLOTVIEW_H

Loading…
Cancel
Save