Optimize plugin-processing for non-automated params
[ardour.git] / libs / ardour / ardour / dsp_load_calculator.h
index f3c5fea2274b356deef886d2996062923734d818..88b327bb300ef8ab85853df680d900aca92248aa 100644 (file)
 #ifndef ARDOUR_DSP_LOAD_CALCULATOR_H
 #define ARDOUR_DSP_LOAD_CALCULATOR_H
 
+#include <stdlib.h>
 #include <stdint.h>
 #include <cassert>
 #include <algorithm>
 
-#include <pbd/ringbuffer.h>
-
-#include "ardour/libardour_visibility.h"
-
 namespace ARDOUR {
 
-class LIBARDOUR_API DSPLoadCalculator {
+class DSPLoadCalculator {
 public:
        DSPLoadCalculator()
            : m_max_time_us(0)
            , m_start_timestamp_us(0)
            , m_stop_timestamp_us(0)
            , m_dsp_load(0)
-           , m_value_history (max_value_history())
-           , m_num_values(0)
        {
 
        }
 
+       void set_max_time(double samplerate, uint32_t period_size) {
+               m_max_time_us = period_size * 1e6 / samplerate;
+       }
+
        void set_max_time_us(uint64_t max_time_us) {
                assert(max_time_us != 0);
                m_max_time_us = max_time_us;
-
-               // Use average of last 1/4 second of values so responsiveness
-               // remains consistent independent of max time
-               uint32_t max_dsp_samples_per_qtr_second = (250000 / m_max_time_us);
-               m_num_values =
-                   std::min(max_value_history() - 1, max_dsp_samples_per_qtr_second);
-
-               m_value_history.reset();
        }
 
-
        int64_t get_max_time_us() const { return m_max_time_us; }
 
        void set_start_timestamp_us(int64_t start_timestamp_us)
@@ -63,7 +53,37 @@ public:
                m_start_timestamp_us = start_timestamp_us;
        }
 
-       void set_stop_timestamp_us(int64_t stop_timestamp_us);
+       void set_stop_timestamp_us(int64_t stop_timestamp_us)
+       {
+               m_stop_timestamp_us = stop_timestamp_us;
+
+               /* querying the performance counter can fail occasionally (-1).
+                * Also on some multi-core systems, timers are CPU specific and not
+                * synchronized. We assume they differ more than a few milliseconds
+                * (4 * nominal cycle time) and simply ignore cases where the
+                * execution switches cores.
+                */
+               if (m_start_timestamp_us < 0 || m_stop_timestamp_us < 0 ||
+                   m_start_timestamp_us > m_stop_timestamp_us ||
+                   elapsed_time_us() > max_timer_error_us()) {
+                       return;
+               }
+
+#ifndef NDEBUG
+               const bool calc_avg_load = NULL != getenv("AVGLOAD");
+#else
+               const bool calc_avg_load = false;
+#endif
+
+               const float load = (float) elapsed_time_us() / (float)m_max_time_us;
+               if ((calc_avg_load && load > .95f) || (!calc_avg_load && (load > m_dsp_load || load > 1.f))) {
+                       m_dsp_load = load;
+               } else {
+                       const float alpha = 0.2f * (m_max_time_us * 1e-6f);
+                       m_dsp_load = std::min (1.f, m_dsp_load);
+                       m_dsp_load += alpha * (load - m_dsp_load) + 1e-12;
+               }
+       }
 
        int64_t elapsed_time_us()
        {
@@ -77,26 +97,32 @@ public:
         */
        float get_dsp_load() const
        {
-               if (m_dsp_load > m_max_time_us) {
-                       return 1.0f;
-               }
-               if (m_dsp_load < 0.0f) {
-                       return 0.0f;
-               }
+               assert (m_dsp_load >= 0.f); // since stop > start is assured this cannot happen.
+               return std::min (1.f, m_dsp_load);
+       }
+
+       /**
+        * @return an unbound value representing the percentage of time spent between
+        * start and stop in proportion to the max expected time in microseconds(us).
+        * This is useful for cases to estimate overload (e.g. Dummy backend)
+        */
+       float get_dsp_load_unbound() const
+       {
+               assert (m_dsp_load >= 0.f);
                return m_dsp_load;
        }
-private: // methods
-       static uint32_t max_value_history () { return 16; }
 
-       int64_t max_timer_error () { return 4 * m_max_time_us; }
+       /**
+        * The maximum error in timestamp values that will be tolerated before the
+        * current dsp load sample will be ignored
+        */
+       int64_t max_timer_error_us() { return 4 * m_max_time_us; }
 
 private: // data
        int64_t m_max_time_us;
        int64_t m_start_timestamp_us;
        int64_t m_stop_timestamp_us;
        float m_dsp_load;
-       RingBuffer<float> m_value_history;
-       uint32_t m_num_values;
 };
 
 } // namespace ARDOUR