View Issue Details

IDProjectCategoryView StatusLast Update
0006567ardourbugspublic2015-09-27 04:26
Reportertimbyr Assigned To 
PrioritynormalSeverityminorReproducibilityalways
Status feedbackResolutionopen 
Product Version4.X git (version in description) 
Summary0006567: DSP load calculations inconsistent between backends
DescriptionEach AudioBackend is responsible for reporting an estimate of DSP load/CPU utilization in the available time slice etc.

Currently the algorithm used for calculating the DSP load is or should be the same for the coreaudio/portaudio and alsa backends. They Jump to max with a LPF roll-off.

Jack2 returns an average of the values unless the the load is over 95%, Or at least that is my impression from reading jack2/common/JackEngineControl.cpp in the Jack2 source.
Additional InformationThis bug is to discuss what we should do for the DSP load calculations in the AudioBackends where we can easily change the algorithm.

The current method used in the CA/PA and ALSA backends is perhaps too variable and a load average would be preferred similar to Jack2.

But I also think that as the processing load can be so variable that we should be returning more accurate values rather than an average over perhaps 80% load and not 95% like Jack2.

Whatever gets decided we should use the same code/class like the DSPLoadCalculator class in the Portaudio backend for all in-tree backends.
TagsNo tags attached.

Activities

johne53

2015-09-08 18:00

reporter   ~0017167

Just for some background... the averaging strategy was introduced when we launched Mixbus (on Windows) because of the unpredictability of readings. Out of (say) 20 consecutive readings, 19 might all be below 20% whereas there always seemed to be a rogue one at around 70%. Displaying the maximum value would therefore give an unreasonably pessimistic impression of typical performance.

A limit of 95% was chosen because it was felt that (once the performance got genuinely close to 100%) this should be flagged up to the user. Therefore no averaging gets done if any value is really high (above 95%). This works well for Mixbus2.

However, for Mixbus3 (and a non-Jack backend) there's anecdotal evidence of users being able to hear glitching with comparatively low DSP readings (even as low as 70%). So yes - a lower figure than 95% might be advisable for Ardour4 and Mixbus3.

timbyr

2015-09-10 05:11

developer   ~0017171

The DSP load calculation in the Portaudio backend is now using an averaging of the values when the load is under 80%.

x42

2015-09-10 13:00

administrator   ~0017172

Last edited: 2015-09-10 13:02

As discussed on IRC, please revert this. If Portaudio needs it, do it the portaudio backend.

Square window averaging, 80% discrimination and a 1st order low-pass, all rolled in one.. My thoughts about this are unwritable.
The value is useless for any reliable measurement. We need to keep some standards when it comes to mathematics and statistics in libardour.

If the API is to become part of libardour it should IMHO be:

  void start_cycle ();
  void end_cycle (uint32_t samples, float samplerate);
  float get_dsp_load() const;

As for the calculation: jump to max (show load spikes, do *not* hide them) and fall-off with a 1st-order low-pass.

x42

2015-09-10 13:05

administrator   ~0017173

PS. an additional user-resettable peak-DSP-load hold (reset when clearing the x-run counter) would be nice for debug versions.

x42

2015-09-10 17:24

administrator   ~0017176

PPS. if you need a "smooth" readout for marketing reasons always low-pass filter it.
The LPF will smoothen the spikes consistently (no need to add a separate averaging buffer)

if (!profile->(mixbus) && cur_load > _dsp_load {
  _dsp_load = load;
} else {
  _dsp_load += flt_coeff * (load - _dsp_load) + NODENORMAL;
}

timbyr

2015-09-10 22:27

developer   ~0017177

This issue is about consistency of dsp load between backends. It is not that the portaudio backend needs to use this method of calculation. It was done as that is basically how jack2 does the calculation and as a large portion of users use jack2 it was an attempt to stay consistent with that.

I can move(not revert) it back into the portaudio backend but that would defeat the purpose of putting it into libardour so that all backends can use it.

You seem to have a strong preference for the method of calculation used in the Coreaudio and ALSA backends which is fine. If other stakeholders want to use another method of calculation for whatever reason(marketing/aesthetics/etc) then I'm assuming they will want it to be used consistently between backends.

I am fine with changing the implementation to what you suggested above of always using a LPF based on a profile/flag. It is worth trying to see if is acceptable anyway.

As for the API suggestions. I chose to use time(usecs/uint64_t) with a set_max_time/set_start_time/set_stop_time style API rather than what you suggest as it means no coupling to the specific timer or limited to use cases involving samples/samplerate(although I can't imagine where else to use it atm).

As the max expected time (samples in microseconds) rarely changes and set_max_time allowed for doing to some pre-calculations which are not necessary with a LPF only approach.

x42

2015-09-10 23:40

administrator   ~0017178

The only reason why ALSA and Coreaudio use <glib> is to call g_get_monotonic_time() to query the time. That part is also common in all cases and if we centralize the API we should take those along as well.

Another idea: Why not go the whole 9 yards: AudioEngine::process_callback() can calculate it, directly in libardour.

We only need to special case JACK, because JACK-DSP load can include load from external apps, an easy way to accomplish this would be to always have AudioEngine::process_callback() calculate DSP-load and provide a default implementation in audio_backend.h which returns the AudioEngine's DSP load.

The downside here, it does not include the time to memcpy/mixdown/byte-convert the buffers (IFF the backend uses memcpy to/from hardware buffers). On Unix I expect this to be negligible, but I don't know how well Portaudio fares there.


PS. Fixing jack2 DSP load reporting is on my ToDo list somewhere, It needs the same approach on Windows as the Ardour Dummy backend to work properly on AMD machines. The "hack" to average in jack was added because of that and we now have a better solution for this.

timbyr

2015-09-11 00:40

developer   ~0017179

Using g_get_monotonic_time may not be appropriate for windows if that is what you are suggesting. It uses timeGetTime which has a resolution limited to 15ms unless you call timeBeginPeriod etc as you are probably aware.

What is the approach you are referring to to detect/fix the problem on AMD machines. Are you referring to QueryPerformanceCounter not working correctly on some hardware? I though that was only on WindowsXP? I couldn't see any code in the DummyBackend that would address this? QueryPerformanceFrequency will still succeed even with non-invariant TSC...?

I think providing a default implementation for calculating in AudioEngine rather than in the backend may work without thinking about it too much. It seems easier/less change to just use the same method/class in the backends though.

x42

2015-09-11 01:12

administrator   ~0017180

yes, QueryPerformanceCounter(). It's not an XP issue, but an issue with some AMD-multi-cores (some of which have independent timers per cpu core).

The process thread does not usually change CPU-cores while it's running (between start and end of one cycle), but in rare cases that it does, we simply ignore the value. Likewise if the timer is busy (can't be read, returns -1).

grep _x_get_monotonic_usec libs/backends/dummy_audiobackend.cc

https://github.com/Ardour/ardour/blob/master/libs/backends/dummy/dummy_audiobackend.cc#L1281

timbyr

2015-09-11 01:38

developer   ~0017181

The only reason I mentioned that I thought it was a XP issue was from reading these docs:
https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx

But on re-reading it doesn't explicitly say that it won't happen on non-XP systems, just that it is less likely to happen with newer hardware.

I'll incorporate a fix for failing to read QPC.

timbyr

2015-09-11 11:36

developer   ~0017182

As mentioned on IRC, I'll be leaving the DSPLoadCalculator class in libardour for now and try to come up with a solution that is acceptable for use in the other backends. If that doesn't work out I will move it back into the PortAudio backend.

timbyr

2015-09-16 03:52

developer   ~0017213

Last edited: 2015-09-16 04:17

The DSPLoadCalculator class is now used in Dummy, ALSA and Portaudio backends as of master@faa38a0d

Fixes for the XP/AMD multi-core issue from the DummyBackend are included, so DSP load should be fixed now on those machines for the PortaudioBackend. Unfortunately I don't have a machine to test that on so we will have to wait for someone with appropriate hardware to confirm.

I have not changed the Coreaudio backend as I don't have access to a system to test it.

timbyr

2015-09-27 04:26

developer   ~0017368

The Coreaudio backend is using the same method of calculation as of 1c43383e so now it is only jack of the 'supported' backends that is using a different method of DSP load calculation.

Issue History

Date Modified Username Field Change
2015-09-08 02:56 timbyr New Issue
2015-09-08 18:00 johne53 Note Added: 0017167
2015-09-10 05:11 timbyr Note Added: 0017171
2015-09-10 05:11 timbyr Status new => feedback
2015-09-10 13:00 x42 Note Added: 0017172
2015-09-10 13:02 x42 Note Edited: 0017172
2015-09-10 13:05 x42 Note Added: 0017173
2015-09-10 17:24 x42 Note Added: 0017176
2015-09-10 22:27 timbyr Note Added: 0017177
2015-09-10 23:40 x42 Note Added: 0017178
2015-09-11 00:40 timbyr Note Added: 0017179
2015-09-11 01:12 x42 Note Added: 0017180
2015-09-11 01:38 timbyr Note Added: 0017181
2015-09-11 11:36 timbyr Note Added: 0017182
2015-09-16 03:52 timbyr Note Added: 0017213
2015-09-16 04:15 timbyr Note Edited: 0017213
2015-09-16 04:17 timbyr Note Edited: 0017213
2015-09-27 04:26 timbyr Note Added: 0017368