diff --git a/libs/global/kis_relaxed_timer.cpp b/libs/global/kis_relaxed_timer.cpp index 00b3691..dfe3f4e 100644 --- a/libs/global/kis_relaxed_timer.cpp +++ b/libs/global/kis_relaxed_timer.cpp @@ -97,6 +97,7 @@ void KisRelaxedTimer::resync() m_emitOnTimeTick = m_nextTimerTickSeqNo; m_timer.start(m_interval, this); m_tick.start(); + m_numberOfRestarts++; } void KisRelaxedTimer::timerEvent(QTimerEvent *event) diff --git a/libs/global/kis_relaxed_timer.h b/libs/global/kis_relaxed_timer.h index 08ca7e7..20a0d7b 100644 --- a/libs/global/kis_relaxed_timer.h +++ b/libs/global/kis_relaxed_timer.h @@ -64,6 +64,8 @@ public: int remainingTime() const; + int m_numberOfRestarts = 0; + Q_SIGNALS: void timeout(); diff --git a/libs/global/kis_signal_compressor.cpp b/libs/global/kis_signal_compressor.cpp index 90e5614..2c4dabb 100644 --- a/libs/global/kis_signal_compressor.cpp +++ b/libs/global/kis_signal_compressor.cpp @@ -47,6 +47,11 @@ void KisSignalCompressor::setDelay(int delay) m_timer->setInterval(delay, 1, delay / 10); } +int KisSignalCompressor::numRestarts() const +{ + return m_timer->m_numberOfRestarts; +} + void KisSignalCompressor::start() { Q_ASSERT(m_mode != UNDEFINED); diff --git a/libs/global/kis_signal_compressor.h b/libs/global/kis_signal_compressor.h index ff2ff7a..33f23eb 100644 --- a/libs/global/kis_signal_compressor.h +++ b/libs/global/kis_signal_compressor.h @@ -74,6 +74,8 @@ public: void setMode(Mode mode); void setDelay(int delay); + int numRestarts() const; + public Q_SLOTS: void start(); void stop(); diff --git a/libs/global/tests/CMakeLists.txt b/libs/global/tests/CMakeLists.txt index 3cc4776..717ae1b 100644 --- a/libs/global/tests/CMakeLists.txt +++ b/libs/global/tests/CMakeLists.txt @@ -6,3 +6,8 @@ macro_add_unittest_definitions() ecm_add_test(KisSharedThreadPoolAdapterTest.cpp TEST_NAME KisSharedThreadPoolAdapter LINK_LIBRARIES kritaglobal Qt5::Test) + +ecm_add_test(KisSignalCompressorTest.cpp + TEST_NAME KisSignalCompressorTest + LINK_LIBRARIES kritaglobal Qt5::Test) + diff --git a/libs/global/tests/KisSignalCompressorTest.cpp b/libs/global/tests/KisSignalCompressorTest.cpp new file mode 100644 index 0000000..3e9f8df --- /dev/null +++ b/libs/global/tests/KisSignalCompressorTest.cpp @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2017 Dmitry Kazakov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "KisSignalCompressorTest.h" + +#include +#include +#include +#include "kis_debug.h" + + +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace boost::accumulators; + +class TimerTester : public QObject +{ + Q_OBJECT +public: + TimerTester(int expectedPeriod, int tickPeriod, int tickVariance, int numEvents) + : m_timer(&m_eventLoop), + m_expectedPeriod(expectedPeriod), + m_desiredPeriod(tickPeriod), + m_desiredVariance(tickVariance), + m_desiredNumEvents(numEvents), + m_rnd(11), // manually crafted very random seed! + m_distribution(tickPeriod, tickVariance) + { + m_timer.setSingleShot(true); + connect(&m_timer, SIGNAL(timeout()), SLOT(timerTick())); + } + + qreal periodMean() const { + return mean(m_accumulator); + } + + qreal periodStandardDeviation() const { + return std::sqrt(lazy_variance(m_accumulator)); + } + + qreal periodMin() const { + return min(m_accumulator); + } + + qreal periodMax() const { + return max(m_accumulator); + } + + qreal positiveOffsetMean() const { + return mean(m_positiveOffsetAccumulator); + } + + qreal positiveOffsetStandardDeviation() const { + return std::sqrt(lazy_variance(m_positiveOffsetAccumulator)); + } + + qreal positiveOffsetMax() const { + return max(m_positiveOffsetAccumulator); + } + + qreal negativeOffsetMean() const { + return mean(m_negativeOffsetAccumulator); + } + + qreal negativeOffsetStandardDeviation() const { + return std::sqrt(lazy_variance(m_negativeOffsetAccumulator)); + } + + qreal negativeOffsetMax() const { + return min(m_negativeOffsetAccumulator); + } + + int realNumberOfTicks() const { + return m_realNumberOfTicks; + } + + void start() { + m_timeSinceLastTick.start(); + m_timer.start(m_distribution(m_rnd)); + + m_eventLoop.exec(); + } + + QEventLoop *eventLoop() { + return &m_eventLoop; + } + +public Q_SLOTS: + void externalTimerTicked() { + const qreal msecTime = m_timeSinceLastTick.nsecsElapsed() / 1000000.0; + + //ENTER_FUNCTION() << ppVar(msecTime); + + m_accumulator(msecTime); + + m_positiveOffsetAccumulator(qMax(0.0, msecTime - qreal(m_expectedPeriod))); + m_negativeOffsetAccumulator(qMin(0.0, msecTime - qreal(m_expectedPeriod))); + + m_timeSinceLastTick.restart(); + + if (int(count(m_accumulator)) >= m_desiredNumEvents) { + m_eventLoop.quit(); + } + } + +Q_SIGNALS: + void sigStartExternalTimer(); + +private Q_SLOTS: + void timerTick() { + emit sigStartExternalTimer(); + m_timer.start(m_distribution(m_rnd)); + m_realNumberOfTicks++; + } + +private: + QEventLoop m_eventLoop; + QTimer m_timer; + int m_expectedPeriod; + int m_desiredPeriod; + int m_desiredVariance; + int m_desiredNumEvents; + int m_realNumberOfTicks = 0; + QElapsedTimer m_timeSinceLastTick; + accumulator_set > m_accumulator; + + accumulator_set > m_negativeOffsetAccumulator; + accumulator_set > m_positiveOffsetAccumulator; + + + boost::random::mt19937 m_rnd; + boost::random::normal_distribution m_distribution; + +}; + +#include + +void KisSignalCompressorTest::test() +{ + const int compressorPeriod = 60; + const int tickPeriod = 30; + + + TimerTester tester(compressorPeriod, tickPeriod, 5, 200); + + // noop testing + // connect(&tester, SIGNAL(sigStartExternalTimer()), &tester, SLOT(externalTimerTicked())); + + KisSignalCompressor compressor(compressorPeriod, KisSignalCompressor::FIRST_ACTIVE, tester.eventLoop()); + connect(&tester, SIGNAL(sigStartExternalTimer()), &compressor, SLOT(start())); + connect(&compressor, SIGNAL(timeout()), &tester, SLOT(externalTimerTicked())); + tester.start(); + + qDebug() << "Period: mean:" << tester.periodMean() << + "st.dev.:" << tester.periodStandardDeviation() << + "min/max:" << tester.periodMin() << tester.periodMax(); + + qDebug() << " +offset: mean:" << tester.positiveOffsetMean() + << "max:" << tester.positiveOffsetMax(); + + qDebug() << " -offset: mean:" << tester.negativeOffsetMean() + << "max:" << tester.negativeOffsetMax(); + + qDebug() << "Ticks:" << tester.realNumberOfTicks() << "Restarts:" << compressor.numRestarts() << qreal(compressor.numRestarts()) / tester.realNumberOfTicks(); +} + +QTEST_MAIN(KisSignalCompressorTest) + +#include "KisSignalCompressorTest.moc" diff --git a/libs/global/tests/KisSignalCompressorTest.h b/libs/global/tests/KisSignalCompressorTest.h new file mode 100644 index 0000000..4208388 --- /dev/null +++ b/libs/global/tests/KisSignalCompressorTest.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017 Dmitry Kazakov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KISSIGNALCOMPRESSORTEST_H +#define KISSIGNALCOMPRESSORTEST_H + +#include + +class KisSignalCompressorTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void test(); +}; + +#endif // KISSIGNALCOMPRESSORTEST_H