summaryrefslogtreecommitdiff
path: root/libs/ardour/ardour/dsp_load_calculator.h
blob: 88b327bb300ef8ab85853df680d900aca92248aa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
 * Copyright (C) 2015 Tim Mayberry <mojofunk@gmail.com>
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#ifndef ARDOUR_DSP_LOAD_CALCULATOR_H
#define ARDOUR_DSP_LOAD_CALCULATOR_H

#include <stdlib.h>
#include <stdint.h>
#include <cassert>
#include <algorithm>

namespace ARDOUR {

class DSPLoadCalculator {
public:
	DSPLoadCalculator()
	    : m_max_time_us(0)
	    , m_start_timestamp_us(0)
	    , m_stop_timestamp_us(0)
	    , m_dsp_load(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;
	}

	int64_t get_max_time_us() const { return m_max_time_us; }

	void set_start_timestamp_us(int64_t start_timestamp_us)
	{
		m_start_timestamp_us = start_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()
	{
		return m_stop_timestamp_us - m_start_timestamp_us;
	}

	/**
	 * @return a decimal value between 0.0 and 1.0 representing the percentage
	 * of time spent between start and stop in proportion to the max expected time
	 * in microseconds(us).
	 */
	float get_dsp_load() const
	{
		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;
	}

	/**
	 * 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;
};

} // namespace ARDOUR

#endif // ARDOUR_DSP_LOAD_CALCULATOR_H