From 23d924643f7cfe2260d18a71b7fee47c47899b05 Mon Sep 17 00:00:00 2001 From: dzmat Date: Mon, 24 Sep 2018 21:44:46 +0700 Subject: [PATCH] Reduce horizontal graphs resolution Rewrite averaging code and reduce horizontal graphs resolution for 30 minutes and 6 hours graphs to decrease CPU usage. --- src/gui/properties/speedplotview.cpp | 93 +++++++++++++++++++--------- src/gui/properties/speedplotview.h | 35 +++++------ 2 files changed, 80 insertions(+), 48 deletions(-) diff --git a/src/gui/properties/speedplotview.cpp b/src/gui/properties/speedplotview.cpp index f00cd0e91..63f41bb96 100644 --- a/src/gui/properties/speedplotview.cpp +++ b/src/gui/properties/speedplotview.cpp @@ -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 &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::getCurrentData( } } -int SpeedPlotView::maxYValue() +quint64 SpeedPlotView::maxYValue() { boost::circular_buffer &queue = getCurrentData(); - int maxYValue = 0; + quint64 maxYValue = 0; for (int id = UP; id < NB_GRAPHS; ++id) { if (!m_properties[static_cast(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(); } diff --git a/src/gui/properties/speedplotview.h b/src/gui/properties/speedplotview.h index ea48e00ee..637282980 100644 --- a/src/gui/properties/speedplotview.h +++ b/src/gui/properties/speedplotview.h @@ -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 - }; - - enum PointsToSave - { - MIN5_BUF_SIZE = 5 * 60, - MIN30_BUF_SIZE = 10 * 60, - HOUR6_BUF_SIZE = 20 * 60 + public: + Averager(int divider, boost::circular_buffer &sink); + void push(const PointData &pointData); + bool isReady() const; + + private: + const int m_divider; + boost::circular_buffer &m_sink; + int m_counter; + PointData m_accumulator; }; struct GraphProperties @@ -111,19 +110,19 @@ private: bool enable; }; - int maxYValue(); + quint64 maxYValue(); boost::circular_buffer &getCurrentData(); boost::circular_buffer m_data5Min; boost::circular_buffer m_data30Min; boost::circular_buffer m_data6Hour; + Averager m_averager30Min; + Averager m_averager6Hour; + QMap m_properties; TimePeriod m_period; int m_viewablePointsCount; - - int m_counter30Min; - int m_counter6Hour; }; #endif // SPEEDPLOTVIEW_H