#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(m_max_time_us != 0);
+ 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; }
- uint64_t get_max_time_us() const { return m_max_time_us; }
-
- void set_start_timestamp_us(uint64_t start_timestamp_us)
+ void set_start_timestamp_us(int64_t start_timestamp_us)
{
m_start_timestamp_us = start_timestamp_us;
}
- void set_stop_timestamp_us(uint64_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;
+ }
+
+ const float load = (float) elapsed_time_us() / (float)m_max_time_us;
+ if (load > m_dsp_load || load > 1.0) {
+ 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;
+ }
+ }
- uint64_t elapsed_time_us()
+ int64_t elapsed_time_us()
{
return m_stop_timestamp_us - m_start_timestamp_us;
}
*/
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; }
+
+ /**
+ * 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
- uint64_t m_max_time_us;
- uint64_t m_start_timestamp_us;
- uint64_t m_stop_timestamp_us;
+ 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