File indexing completed on 2024-05-12 15:56:58

0001 /*
0002  *  SPDX-FileCopyrightText: 2017 Bernhard Liebl <poke1024@gmx.de>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef KRITA_KIS_SCALAR_TRACKER_H
0008 #define KRITA_KIS_SCALAR_TRACKER_H
0009 
0010 #include "kis_shared.h"
0011 #include <kritaglobal_export.h>
0012 
0013 #include <QQueue>
0014 #include <QElapsedTimer>
0015 #include <QDebug>
0016 
0017 #include <boost/heap/fibonacci_heap.hpp>
0018 
0019 #include <boost/accumulators/accumulators.hpp>
0020 #include <boost/accumulators/statistics/stats.hpp>
0021 #include <boost/accumulators/statistics/rolling_mean.hpp>
0022 #include <boost/accumulators/statistics/rolling_variance.hpp>
0023 
0024 template<typename T>
0025 class KisRollingMax {
0026 public:
0027     KisRollingMax(int windowSize) : m_windowSize(windowSize) {
0028     }
0029 
0030     void push(T value) {
0031         while (m_samples.size() > m_windowSize) {
0032             m_values.erase(m_samples.dequeue());
0033         }
0034 
0035         m_samples.enqueue(m_values.push(value));
0036     }
0037 
0038     T max() const {
0039         if (m_values.empty()) {
0040             throw std::runtime_error("no values to get max of");
0041         } else {
0042             return m_values.top();
0043         }
0044     }
0045 
0046 private:
0047     const int m_windowSize;
0048 
0049     typedef boost::heap::fibonacci_heap<T> heap_type;
0050 
0051     QQueue<typename heap_type::handle_type> m_samples;
0052     heap_type m_values;
0053 };
0054 
0055 template<typename T>
0056 class KisScalarTracker : public KisShared {
0057 public:
0058     /**
0059      * Create a tracker with the given window size.
0060      * @param window The maximum number of elements to take into account for calculation
0061      * of max, mean and variance values.
0062      */
0063     KisScalarTracker(const QString &name, int windowSize = 500) :
0064         m_name(name),
0065         m_windowSize(windowSize),
0066         m_addCount(0),
0067         m_max(windowSize),
0068         m_acc(boost::accumulators::tag::rolling_window::window_size = windowSize)
0069     {
0070         m_printTimer.start();
0071     }
0072 
0073     virtual ~KisScalarTracker() {
0074     }
0075 
0076     /**
0077      * Add a scalar.
0078      * @param value the scalar to be added.
0079      */
0080     virtual void push(T value) {
0081         m_max.push(value);
0082         m_acc(value);
0083         m_addCount++;
0084 
0085         if (m_addCount >= m_windowSize || m_printTimer.elapsed() >= 1000) {
0086             m_printTimer.restart();
0087             QString s = format(boost::accumulators::rolling_mean(m_acc),
0088                   boost::accumulators::rolling_variance(m_acc),
0089                   m_max.max());
0090             print(s);
0091             m_addCount = 0;
0092         }
0093 
0094     }
0095 
0096 protected:
0097     /**
0098      * Print out a message.
0099      * @param message the message to print
0100      */
0101     virtual void print(const QString &message) {
0102         qInfo() << qUtf8Printable(message);
0103     }
0104 
0105     /**
0106      * Formats a message for printing.
0107      * @param mean the mean scalar in the window
0108      * @param variance the variance of the scalar in the window
0109      * @param max the max scalar in the window
0110      */
0111     virtual QString format(qint64 mean, qint64 variance, qint64 max) {
0112         return QString("%1: mean %2 ms, var %3, max %4 ms").arg(m_name).arg(mean).arg(variance).arg(max);
0113     }
0114 
0115 private:
0116     const QString m_name;
0117     const int m_windowSize;
0118     int m_addCount;
0119 
0120     QElapsedTimer m_printTimer;
0121 
0122     KisRollingMax<T> m_max;
0123 
0124     // see https://svn.boost.org/trac10/ticket/11437
0125     typedef boost::accumulators::stats<
0126         boost::accumulators::tag::lazy_rolling_mean,
0127         boost::accumulators::tag::rolling_variance> stats;
0128 
0129     boost::accumulators::accumulator_set<T, stats> m_acc;
0130 };
0131 
0132 /**
0133  * KisLatencyTracker tracks the time it takes events to reach a certain point in the program.
0134  */
0135 
0136 class KRITAGLOBAL_EXPORT KisLatencyTracker : public KisScalarTracker<qint64> {
0137 public:
0138     /**
0139      * Create a tracker with the given window size.
0140      * @param window The maximum number of elements to take into account for calculation
0141      * of max, mean and variance values.
0142      */
0143     KisLatencyTracker(int windowSize = 500);
0144 
0145     /**
0146      * Register that an event with the given timestamp has arrived just now.
0147      * @param timestamp Timestamp of the event that just arrived (the difference to the
0148      * current time is the latency).
0149      */
0150     virtual void push(qint64 timestamp) override;
0151 
0152 protected:
0153     /**
0154      * @return The timestamp of "right now" in a frame that is comparable to those
0155      * timestamps given to push().
0156      */
0157     virtual qint64 currentTimestamp() const = 0;
0158 };
0159 
0160 #endif //KRITA_KIS_SCALAR_TRACKER_H