audit syscalls made from the PortAudio callback

Bug #1648280 reported by RJ Skerry-Ryan
8
This bug affects 1 person
Affects Status Importance Assigned to Milestone
Mixxx
Confirmed
Undecided
Unassigned

Bug Description

I've been examining the syscalls Mixxx makes from the PortAudio thread with dtrace to try and measure their cost. We should minimize the syscalls we do in a realtime context to avoid blocking the engine thread.

RJ Skerry-Ryan (rryan)
Changed in mixxx:
status: New → Confirmed
Revision history for this message
RJ Skerry-Ryan (rryan) wrote :
Download full text (3.7 KiB)

gettimeofday appears to take about 8 microseconds on average. The "ts" here is a walltime nanosecond counter (though I think the precision is microseconds, not nanos since the last 3 numbers are always zero).

Notably, I'm not broadcasting at all and EngineNetworkStream is still doing this work.

  0 383 gettimeofday:return (tid 1488971) ts:1481161656405619000 gettimeofday
              libsystem_kernel.dylib`__gettimeofday+0xa
              mixxx`EngineNetworkStream::getWriteExpected()+0x17
              mixxx`SoundDeviceNetwork::writeProcess()+0xd4
              mixxx`SoundManager::writeProcess()+0xb9
              mixxx`SoundDevicePortAudio::callbackProcessClkRef(unsigned int, float*, float const*, PaStreamCallbackTimeInfo const*, unsigned long)+0x751
              mixxx`(anonymous namespace)::paV19CallbackClkRef(void const*, void*, unsigned long, PaStreamCallbackTimeInfo const*, unsigned long, void*)+0x23
              libportaudio.2.dylib`AdaptingOutputOnlyProcess+0xe7
              libportaudio.2.dylib`PaUtil_EndBufferProcessing+0x1c4
              libportaudio.2.dylib`AudioIOProc+0x392
              CoreAudio`AUConverterBase::RenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int)+0x2c5
              CoreAudio`AUBase::DoRenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, AUOutputElement*, unsigned int, AudioBufferList&)+0x9a
              CoreAudio`AUBase::DoRender(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int, AudioBufferList&)+0x1f8
              CoreAudio`AUHAL::AUIOProc(unsigned int, AudioTimeStamp const*, AudioBufferList const*, AudioTimeStamp const*, AudioBufferList*, AudioTimeStamp const*, void*)+0x6f2
              CoreAudio`HALC_ProxyIOContext::IOWorkLoop()+0x9e7
              CoreAudio`HALC_ProxyIOContext::IOThreadEntry(void*)+0x58
              CoreAudio`HALB_IOThread::Entry(void*)+0x4b
              libsystem_pthread.dylib`_pthread_body+0x83
              libsystem_pthread.dylib`_pthread_body
              libsystem_pthread.dylib`thread_start+0xd

  0 382 gettimeofday:entry (tid 1488971) ts:1481161656407042000 gettimeofday
              libsystem_kernel.dylib`__gettimeofday+0xa
              mixxx`EngineNetworkStream::getWriteExpected()+0x17
              mixxx`SoundDeviceNetwork::writeProcess()+0xd4
              mixxx`SoundManager::writeProcess()+0xb9
              mixxx`SoundDevicePortAudio::callbackProcessClkRef(unsigned int, float*, float const*, PaStreamCallbackTimeInfo const*, unsigned long)+0x751
              mixxx`(anonymous namespace)::paV19CallbackClkRef(void const*, void*, unsigned long, PaStreamCallbackTimeInfo const*, unsigned long, void*)+0x23
              libportaudio.2.dylib`AdaptingOutputOnlyProcess+0xe7
              libportaudio.2.dylib`PaUtil_EndBufferProcessing+0x1c4
              libportaudio.2.dylib`AudioIOProc+0x392
              CoreAudio`AUConverterBase::RenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int)+0x2c5
              CoreAudio`AUBase::DoRenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, AUOutputElement*, unsigned int, AudioBufferList&)+0x9a
              CoreAudio`AUBase:...

Read more...

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :
Download full text (3.5 KiB)

EngineSideChain::wakeAll -- 14 microseconds (from one sample)

  0 756 psynch_cvbroad:entry (tid 1488971) ts:1481161657003383000 psynch_cvbroad
              libsystem_kernel.dylib`__psynch_cvbroad+0xa
              QtCore`QWaitCondition::wakeAll()+0x3c
              mixxx`EngineSideChain::writeSamples(float const*, int)+0x109
              mixxx`EngineMaster::process(int)+0xaca
              mixxx`SoundDevicePortAudio::callbackProcessClkRef(unsigned int, float*, float const*, PaStreamCallbackTimeInfo const*, unsigned long)+0x661
              mixxx`(anonymous namespace)::paV19CallbackClkRef(void const*, void*, unsigned long, PaStreamCallbackTimeInfo const*, unsigned long, void*)+0x23
              libportaudio.2.dylib`AdaptingOutputOnlyProcess+0xe7
              libportaudio.2.dylib`PaUtil_EndBufferProcessing+0x1c4
              libportaudio.2.dylib`AudioIOProc+0x392
              CoreAudio`AUConverterBase::RenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int)+0x2c5
              CoreAudio`AUBase::DoRenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, AUOutputElement*, unsigned int, AudioBufferList&)+0x9a
              CoreAudio`AUBase::DoRender(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int, AudioBufferList&)+0x1f8
              CoreAudio`AUHAL::AUIOProc(unsigned int, AudioTimeStamp const*, AudioBufferList const*, AudioTimeStamp const*, AudioBufferList*, AudioTimeStamp const*, void*)+0x6f2
              CoreAudio`HALC_ProxyIOContext::IOWorkLoop()+0x9e7
              CoreAudio`HALC_ProxyIOContext::IOThreadEntry(void*)+0x58
              CoreAudio`HALB_IOThread::Entry(void*)+0x4b
              libsystem_pthread.dylib`_pthread_body+0x83
              libsystem_pthread.dylib`_pthread_body
              libsystem_pthread.dylib`thread_start+0xd

  0 757 psynch_cvbroad:return (tid 1488971) ts:1481161657003397000 psynch_cvbroad
              libsystem_kernel.dylib`__psynch_cvbroad+0xa
              QtCore`QWaitCondition::wakeAll()+0x3c
              mixxx`EngineSideChain::writeSamples(float const*, int)+0x109
              mixxx`EngineMaster::process(int)+0xaca
              mixxx`SoundDevicePortAudio::callbackProcessClkRef(unsigned int, float*, float const*, PaStreamCallbackTimeInfo const*, unsigned long)+0x661
              mixxx`(anonymous namespace)::paV19CallbackClkRef(void const*, void*, unsigned long, PaStreamCallbackTimeInfo const*, unsigned long, void*)+0x23
              libportaudio.2.dylib`AdaptingOutputOnlyProcess+0xe7
              libportaudio.2.dylib`PaUtil_EndBufferProcessing+0x1c4
              libportaudio.2.dylib`AudioIOProc+0x392
              CoreAudio`AUConverterBase::RenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int)+0x2c5
              CoreAudio`AUBase::DoRenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, AUOutputElement*, unsigned int, AudioBufferList&)+0x9a
              CoreAudio`AUBase::DoRender(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int, AudioBufferList&)+0x1f8
              CoreAudio`AUHAL::AUIOProc(unsigned int, AudioTimeStamp const*, AudioBufferList const*, AudioTimeStamp const*, Au...

Read more...

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

I need to update my dtrace scripts to measure the distributions of times rather than eyeballing it. For now, consider every timestamp I give to be a sample size of 1 :).

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :
Download full text (4.1 KiB)

Setting controls for queued connections -- 12 microseconds

  0 752 psynch_mutexwait:entry (tid 1488971) ts:1481161658531164000 psynch_mutexwait
              libsystem_kernel.dylib`__psynch_mutexwait+0xa
              libsystem_pthread.dylib`_pthread_mutex_lock_slow+0x12c
              CoreFoundation`CFRunLoopWakeUp+0x4b
              QtGui`QEventDispatcherMac::wakeUp()+0x30
              QtCore`QCoreApplication::postEvent(QObject*, QEvent*, int)+0x12f
              QtCore`QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+0x55a
              mixxx`ControlDoublePrivate::valueChanged(double, QObject*)+0x4a
              mixxx`ControlDoublePrivate::set(double, QObject*)+0x8e
              mixxx`SoundDevicePortAudio::callbackProcessClkRef(unsigned int, float*, float const*, PaStreamCallbackTimeInfo const*, unsigned long)+0x7a9
              mixxx`(anonymous namespace)::paV19CallbackClkRef(void const*, void*, unsigned long, PaStreamCallbackTimeInfo const*, unsigned long, void*)+0x23
              libportaudio.2.dylib`AdaptingOutputOnlyProcess+0xe7
              libportaudio.2.dylib`PaUtil_EndBufferProcessing+0x1c4
              libportaudio.2.dylib`AudioIOProc+0x392
              CoreAudio`AUConverterBase::RenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int)+0x2c5
              CoreAudio`AUBase::DoRenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, AUOutputElement*, unsigned int, AudioBufferList&)+0x9a
              CoreAudio`AUBase::DoRender(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int, AudioBufferList&)+0x1f8
              CoreAudio`AUHAL::AUIOProc(unsigned int, AudioTimeStamp const*, AudioBufferList const*, AudioTimeStamp const*, AudioBufferList*, AudioTimeStamp const*, void*)+0x6f2
              CoreAudio`HALC_ProxyIOContext::IOWorkLoop()+0x9e7
              CoreAudio`HALC_ProxyIOContext::IOThreadEntry(void*)+0x58
              CoreAudio`HALB_IOThread::Entry(void*)+0x4b
              libsystem_pthread.dylib`_pthread_body+0x83
              libsystem_pthread.dylib`_pthread_body
              libsystem_pthread.dylib`thread_start+0xd

  0 753 psynch_mutexwait:return (tid 1488971) ts:1481161658531176000 psynch_mutexwait
              libsystem_kernel.dylib`__psynch_mutexwait+0xa
              libsystem_pthread.dylib`_pthread_mutex_lock_slow+0x12c
              CoreFoundation`CFRunLoopWakeUp+0x4b
              QtGui`QEventDispatcherMac::wakeUp()+0x30
              QtCore`QCoreApplication::postEvent(QObject*, QEvent*, int)+0x12f
              QtCore`QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+0x55a
              mixxx`ControlDoublePrivate::valueChanged(double, QObject*)+0x4a
              mixxx`ControlDoublePrivate::set(double, QObject*)+0x8e
              mixxx`SoundDevicePortAudio::callbackProcessClkRef(unsigned int, float*, float const*, PaStreamCallbackTimeInfo const*, unsigned long)+0x7a9
              mixxx`(anonymous namespace)::paV19CallbackClkRef(void const*, void*, unsigned long, PaStreamCallbackTimeInfo const*, unsigned long, void*)+0x23
              libportaudio.2.dylib`AdaptingOutputOnlyProcess+0xe7
              libportau...

Read more...

tags: added: engine performance
Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

To verify the dtrace timings make sense I recorded some playing a single MP3 with --developer and compared them with this dtrace script:

HALC_IO*:::IOProc_Begin
/execname == "mixxx"/
{
  self->callback_tid = tid;
  self->callback_enter_ts = timestamp;
  self->callback_enter_vts = vtimestamp;
}

HALC_IO*:::IOProc_End
/execname == "mixxx" && self->callback_enter_ts/
{
  @[ustack(), "callback duration ns"] = quantize(timestamp - self->callback_enter_ts);
  @[ustack(), "callback on-cpu duration ns"] = quantize(vtimestamp - self->callback_enter_vts);
  self->callback_enter_ts = 0;
  self->callback_enter_vts = 0;
}

Debug [Main]: Stat("SoundDevicePortAudio::callbackProcessClkRef 1, Built-in Output_duration","count=47361,average=67407.8ns,min=16148ns,max=2.09314e+06ns,variance=1.57389e+09ns^2,stddev=39672.3ns")

I used Mixxx's experiment mode to measure 30 seconds of playing, not including Mixxx startup or shutdown (since that tends to trigger outliers).

  callback on-cpu duration ns
           value ------------- Distribution ------------- count
            8192 | 0
           16384 | 164
           32768 |@@@@@@@@@@@@@ 10218
           65536 |@@@@@@@@@@@@@@@@@@@@@ 16484
          131072 |@@@@@ 3755
          262144 | 71
          524288 | 0
         1048576 | 1
         2097152 | 0

  callback duration ns
           value ------------- Distribution ------------- count
            8192 | 0
           16384 | 43
           32768 |@@@@@@@@@ 6981
           65536 |@@@@@@@@@@@@@@@@@@ 13896
          131072 |@@@@@@@@@@@@ 9293
          262144 |@ 475
          524288 | 3
         1048576 | 1
         2097152 | 1
         4194304 | 0

The min and maxes line up pretty well, so I think I can trust these measurements. I think the difference in max values from the on-cpu vs. on-cpu+off-cpu duration indicates the thread is spending up to a millisecond blocked.

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

Here's a syscall from Stat::track:

              libsystem_kernel.dylib`__psynch_cvbroad+0xa
              QtCore`QWaitCondition::wakeAll()+0x3c
              mixxx`StatsManager::maybeWriteReport(StatReport const&)+0x53
              mixxx`Stat::track(QString const&, Stat::StatType, int, double)+0xae
              mixxx`Timer::elapsed(bool)+0x55
              mixxx`ChannelMixer::mixChannelsRamping(EngineMaster::GainCalculator const&, QVarLengthArray<EngineMaster::ChannelInfo*, 64>*, QVarLengthArray<EngineMaster::GainCache, 64>*, float*, unsigned int)+0xc0
              mixxx`EngineMaster::process(int)+0x1e2
              mixxx`SoundDevicePortAudio::callbackProcessClkRef(unsigned int, float*, float const*, PaStreamCallbackTimeInfo const*, unsigned long)+0x661
              mixxx`(anonymous namespace)::paV19CallbackClkRef(void const*, void*, unsigned long, PaStreamCallbackTimeInfo const*, unsigned long, void*)+0x23
              libportaudio.2.dylib`AdaptingOutputOnlyProcess+0xe7
              libportaudio.2.dylib`PaUtil_EndBufferProcessing+0x1c4
              libportaudio.2.dylib`AudioIOProc+0x392
              CoreAudio`AUConverterBase::RenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int)+0x2c5
              CoreAudio`AUBase::DoRenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, AUOutputElement*, unsigned int, AudioBufferList&)+0x9a
              CoreAudio`AUBase::DoRender(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int, AudioBufferList&)+0x1f8
              CoreAudio`AUHAL::AUIOProc(unsigned int, AudioTimeStamp const*, AudioBufferList const*, AudioTimeStamp const*, AudioBufferList*, AudioTimeStamp const*, void*)+0x6f2
              CoreAudio`HALC_ProxyIOContext::IOWorkLoop()+0x9e7
              CoreAudio`HALC_ProxyIOContext::IOThreadEntry(void*)+0x58
              CoreAudio`HALB_IOThread::Entry(void*)+0x4b
              libsystem_pthread.dylib`_pthread_body+0x83
  syscall duration ns
           value ------------- Distribution ------------- count
            4096 | 0
            8192 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
           16384 | 0

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

              libsystem_kernel.dylib`madvise+0xa
              librubberband.dylib`RubberBand::RingBuffer<float>::~RingBuffer()+0xf
              librubberband.dylib`RubberBand::RubberBandStretcher::Impl::ChannelData::~ChannelData()+0x62
              librubberband.dylib`RubberBand::RubberBandStretcher::Impl::~Impl()+0x162
              librubberband.dylib`RubberBand::RubberBandStretcher::~RubberBandStretcher()+0x17
              mixxx`EngineBufferScaleRubberBand::initRubberBand()+0x57
              mixxx`EngineBuffer::process(float*, int)+0xac
              mixxx`EngineDeck::process(float*, int)+0x123
              mixxx`EngineMaster::processChannels(int)+0x654
              mixxx`EngineMaster::process(int)+0x135
              mixxx`SoundDevicePortAudio::callbackProcessClkRef(unsigned int, float*, float const*, PaStreamCallbackTimeInfo const*, unsigned long)+0x661
              mixxx`(anonymous namespace)::paV19CallbackClkRef(void const*, void*, unsigned long, PaStreamCallbackTimeInfo const*, unsigned long, void*)+0x23
              libportaudio.2.dylib`AdaptingOutputOnlyProcess+0xe7
              libportaudio.2.dylib`PaUtil_EndBufferProcessing+0x1c4
              libportaudio.2.dylib`AudioIOProc+0x392
              CoreAudio`AUConverterBase::RenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int)+0x2c5
              CoreAudio`AUBase::DoRenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, AUOutputElement*, unsigned int, AudioBufferList&)+0x9a
              CoreAudio`AUBase::DoRender(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int, AudioBufferList&)+0x1f8
              CoreAudio`AUHAL::AUIOProc(unsigned int, AudioTimeStamp const*, AudioBufferList const*, AudioTimeStamp const*, AudioBufferList*, AudioTimeStamp const*, void*)+0x6f2
              CoreAudio`HALC_ProxyIOContext::IOWorkLoop()+0x9e7
  syscall duration ns
           value ------------- Distribution ------------- count
            2048 | 0
            4096 |@@@@@@@@@@@@@@@@@@@@ 1
            8192 |@@@@@@@@@@@@@@@@@@@@ 1
           16384 | 0

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

Ouch, malloc. That's about as long as my average callback duration.

              libsystem_kernel.dylib`madvise+0xa
              libsystem_malloc.dylib`malloc_zone_malloc+0x47
              libsystem_malloc.dylib`malloc+0x2a
              libc++.1.dylib`operator new(unsigned long)+0x1e
              QtCore`QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+0x4d1
              mixxx`ControlDoublePrivate::valueChanged(double, QObject*)+0x4a
              mixxx`ControlDoublePrivate::set(double, QObject*)+0x8e
              mixxx`EngineVuMeter::process(float*, int)+0x1e7
              mixxx`EngineMaster::process(int)+0xaeb
              mixxx`SoundDevicePortAudio::callbackProcessClkRef(unsigned int, float*, float const*, PaStreamCallbackTimeInfo const*, unsigned long)+0x661
              mixxx`(anonymous namespace)::paV19CallbackClkRef(void const*, void*, unsigned long, PaStreamCallbackTimeInfo const*, unsigned long, void*)+0x23
              libportaudio.2.dylib`AdaptingOutputOnlyProcess+0xe7
              libportaudio.2.dylib`PaUtil_EndBufferProcessing+0x1c4
              libportaudio.2.dylib`AudioIOProc+0x392
              CoreAudio`AUConverterBase::RenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int)+0x2c5
              CoreAudio`AUBase::DoRenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, AUOutputElement*, unsigned int, AudioBufferList&)+0x9a
              CoreAudio`AUBase::DoRender(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int, AudioBufferList&)+0x1f8
              CoreAudio`AUHAL::AUIOProc(unsigned int, AudioTimeStamp const*, AudioBufferList const*, AudioTimeStamp const*, AudioBufferList*, AudioTimeStamp const*, void*)+0x6f2
              CoreAudio`HALC_ProxyIOContext::IOWorkLoop()+0x9e7
              CoreAudio`HALC_ProxyIOContext::IOThreadEntry(void*)+0x58
  syscall duration ns
           value ------------- Distribution ------------- count
           32768 | 0
           65536 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
          131072 | 0

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

              libsystem_kernel.dylib`__psynch_mutexdrop+0xa
              CoreFoundation`CFRunLoopWakeUp+0xf0
              QtGui`QEventDispatcherMac::wakeUp()+0x30
              QtCore`QCoreApplication::postEvent(QObject*, QEvent*, int)+0x12f
              QtCore`QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+0x55a
              mixxx`ControlDoublePrivate::valueChanged(double, QObject*)+0x4a
              mixxx`ControlDoublePrivate::set(double, QObject*)+0x8e
              mixxx`EngineBuffer::updateIndicators(double, int)+0x110
              mixxx`EngineMaster::processChannels(int)+0x6b3
              mixxx`EngineMaster::process(int)+0x135
              mixxx`SoundDevicePortAudio::callbackProcessClkRef(unsigned int, float*, float const*, PaStreamCallbackTimeInfo const*, unsigned long)+0x661
              mixxx`(anonymous namespace)::paV19CallbackClkRef(void const*, void*, unsigned long, PaStreamCallbackTimeInfo const*, unsigned long, void*)+0x23
              libportaudio.2.dylib`AdaptingOutputOnlyProcess+0xe7
              libportaudio.2.dylib`PaUtil_EndBufferProcessing+0x1c4
              libportaudio.2.dylib`AudioIOProc+0x392
              CoreAudio`AUConverterBase::RenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int)+0x2c5
              CoreAudio`AUBase::DoRenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, AUOutputElement*, unsigned int, AudioBufferList&)+0x9a
              CoreAudio`AUBase::DoRender(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int, AudioBufferList&)+0x1f8
              CoreAudio`AUHAL::AUIOProc(unsigned int, AudioTimeStamp const*, AudioBufferList const*, AudioTimeStamp const*, AudioBufferList*, AudioTimeStamp const*, void*)+0x6f2
              CoreAudio`HALC_ProxyIOContext::IOWorkLoop()+0x9e7
  syscall duration ns
           value ------------- Distribution ------------- count
            2048 | 0
            4096 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 16
            8192 |@@@@ 2
           16384 | 0

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

              libsystem_kernel.dylib`__psynch_mutexdrop+0xa
              QtCore`QWaitCondition::wakeAll()+0x55
              mixxx`EngineSideChain::writeSamples(float const*, int)+0x109
              mixxx`EngineMaster::process(int)+0xaca
              mixxx`SoundDevicePortAudio::callbackProcessClkRef(unsigned int, float*, float const*, PaStreamCallbackTimeInfo const*, unsigned long)+0x661
              mixxx`(anonymous namespace)::paV19CallbackClkRef(void const*, void*, unsigned long, PaStreamCallbackTimeInfo const*, unsigned long, void*)+0x23
              libportaudio.2.dylib`AdaptingOutputOnlyProcess+0xe7
              libportaudio.2.dylib`PaUtil_EndBufferProcessing+0x1c4
              libportaudio.2.dylib`AudioIOProc+0x392
              CoreAudio`AUConverterBase::RenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int)+0x2c5
              CoreAudio`AUBase::DoRenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, AUOutputElement*, unsigned int, AudioBufferList&)+0x9a
              CoreAudio`AUBase::DoRender(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int, AudioBufferList&)+0x1f8
              CoreAudio`AUHAL::AUIOProc(unsigned int, AudioTimeStamp const*, AudioBufferList const*, AudioTimeStamp const*, AudioBufferList*, AudioTimeStamp const*, void*)+0x6f2
              CoreAudio`HALC_ProxyIOContext::IOWorkLoop()+0x9e7
              CoreAudio`HALC_ProxyIOContext::IOThreadEntry(void*)+0x58
              CoreAudio`HALB_IOThread::Entry(void*)+0x4b
              libsystem_pthread.dylib`_pthread_body+0x83
              libsystem_pthread.dylib`_pthread_body
              libsystem_pthread.dylib`thread_start+0xd
  syscall duration ns
           value ------------- Distribution ------------- count
            2048 | 0
            4096 |@@@@@@@@@@@@@ 4
            8192 |@@@@@@@@@@@@@@@@@@@@@@@ 7
           16384 |@@@ 1
           32768 | 0

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

              libsystem_kernel.dylib`madvise+0xa
              mixxx`QHash<int, CachingReaderChunkForOwner*>::remove(int const&)+0x152
              mixxx`CachingReader::freeChunk(CachingReaderChunkForOwner*)+0x75
              mixxx`CachingReader::allocateChunkExpireLRU(long)+0x33
              mixxx`CachingReader::hintAndMaybeWake(QVarLengthArray<Hint, 512> const&)+0x33b
              mixxx`EngineBuffer::hintReader(double)+0x1a0
              mixxx`EngineBuffer::process(float*, int)+0xa88
              mixxx`EngineDeck::process(float*, int)+0x123
              mixxx`EngineMaster::processChannels(int)+0x654
              mixxx`EngineMaster::process(int)+0x135
              mixxx`SoundDevicePortAudio::callbackProcessClkRef(unsigned int, float*, float const*, PaStreamCallbackTimeInfo const*, unsigned long)+0x661
              mixxx`(anonymous namespace)::paV19CallbackClkRef(void const*, void*, unsigned long, PaStreamCallbackTimeInfo const*, unsigned long, void*)+0x23
              libportaudio.2.dylib`AdaptingOutputOnlyProcess+0xe7
              libportaudio.2.dylib`PaUtil_EndBufferProcessing+0x1c4
              libportaudio.2.dylib`AudioIOProc+0x392
              CoreAudio`AUConverterBase::RenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int)+0x2c5
              CoreAudio`AUBase::DoRenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, AUOutputElement*, unsigned int, AudioBufferList&)+0x9a
              CoreAudio`AUBase::DoRender(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int, AudioBufferList&)+0x1f8
              CoreAudio`AUHAL::AUIOProc(unsigned int, AudioTimeStamp const*, AudioBufferList const*, AudioTimeStamp const*, AudioBufferList*, AudioTimeStamp const*, void*)+0x6f2
              CoreAudio`HALC_ProxyIOContext::IOWorkLoop()+0x9e7
  syscall duration ns
           value ------------- Distribution ------------- count
            4096 | 0
            8192 |@@@@@@@@@@@@@@@ 3
           16384 |@@@@@@@@@@@@@@@@@@@@@@@@@ 5
           32768 | 0

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

              libsystem_kernel.dylib`__psynch_cvbroad+0xa
              QtCore`QWaitCondition::wakeAll()+0x3c
              mixxx`EngineSideChain::writeSamples(float const*, int)+0x109
              mixxx`EngineMaster::process(int)+0xaca
              mixxx`SoundDevicePortAudio::callbackProcessClkRef(unsigned int, float*, float const*, PaStreamCallbackTimeInfo const*, unsigned long)+0x661
              mixxx`(anonymous namespace)::paV19CallbackClkRef(void const*, void*, unsigned long, PaStreamCallbackTimeInfo const*, unsigned long, void*)+0x23
              libportaudio.2.dylib`AdaptingOutputOnlyProcess+0xe7
              libportaudio.2.dylib`PaUtil_EndBufferProcessing+0x1c4
              libportaudio.2.dylib`AudioIOProc+0x392
              CoreAudio`AUConverterBase::RenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int)+0x2c5
              CoreAudio`AUBase::DoRenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, AUOutputElement*, unsigned int, AudioBufferList&)+0x9a
              CoreAudio`AUBase::DoRender(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int, AudioBufferList&)+0x1f8
              CoreAudio`AUHAL::AUIOProc(unsigned int, AudioTimeStamp const*, AudioBufferList const*, AudioTimeStamp const*, AudioBufferList*, AudioTimeStamp const*, void*)+0x6f2
              CoreAudio`HALC_ProxyIOContext::IOWorkLoop()+0x9e7
              CoreAudio`HALC_ProxyIOContext::IOThreadEntry(void*)+0x58
              CoreAudio`HALB_IOThread::Entry(void*)+0x4b
              libsystem_pthread.dylib`_pthread_body+0x83
              libsystem_pthread.dylib`_pthread_body
              libsystem_pthread.dylib`thread_start+0xd
  syscall duration ns
           value ------------- Distribution ------------- count
            2048 | 0
            4096 | 1
            8192 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 58
           16384 |@@@@@@@@@@@ 23
           32768 | 0

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

              libsystem_kernel.dylib`__psynch_mutexdrop+0xa
              CoreFoundation`CFRunLoopWakeUp+0xf0
              QtGui`QEventDispatcherMac::wakeUp()+0x30
              QtCore`QCoreApplication::postEvent(QObject*, QEvent*, int)+0x12f
              QtCore`QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+0x55a
              mixxx`ControlDoublePrivate::valueChanged(double, QObject*)+0x4a
              mixxx`ControlDoublePrivate::set(double, QObject*)+0x8e
              mixxx`SoundDevicePortAudio::callbackProcessClkRef(unsigned int, float*, float const*, PaStreamCallbackTimeInfo const*, unsigned long)+0x7a9
              mixxx`(anonymous namespace)::paV19CallbackClkRef(void const*, void*, unsigned long, PaStreamCallbackTimeInfo const*, unsigned long, void*)+0x23
              libportaudio.2.dylib`AdaptingOutputOnlyProcess+0xe7
              libportaudio.2.dylib`PaUtil_EndBufferProcessing+0x1c4
              libportaudio.2.dylib`AudioIOProc+0x392
              CoreAudio`AUConverterBase::RenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int)+0x2c5
              CoreAudio`AUBase::DoRenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, AUOutputElement*, unsigned int, AudioBufferList&)+0x9a
              CoreAudio`AUBase::DoRender(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int, AudioBufferList&)+0x1f8
              CoreAudio`AUHAL::AUIOProc(unsigned int, AudioTimeStamp const*, AudioBufferList const*, AudioTimeStamp const*, AudioBufferList*, AudioTimeStamp const*, void*)+0x6f2
              CoreAudio`HALC_ProxyIOContext::IOWorkLoop()+0x9e7
              CoreAudio`HALC_ProxyIOContext::IOThreadEntry(void*)+0x58
              CoreAudio`HALB_IOThread::Entry(void*)+0x4b
              libsystem_pthread.dylib`_pthread_body+0x83
  syscall duration ns
           value ------------- Distribution ------------- count
            2048 | 0
            4096 |@@@@@@@@@@@@@@@@@@@@@@@@@@@ 118
            8192 |@@@@@@@@@@@@ 51
           16384 |@@ 7
           32768 | 1
           65536 | 0

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :
Download full text (4.6 KiB)

              libsystem_kernel.dylib`__psynch_mutexwait+0xa
              libsystem_pthread.dylib`_pthread_mutex_lock_slow+0x12c
              CoreFoundation`CFRunLoopWakeUp+0x4b
              QtGui`QEventDispatcherMac::wakeUp()+0x30
              QtCore`QCoreApplication::postEvent(QObject*, QEvent*, int)+0x12f
              QtCore`QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+0x55a
              mixxx`ControlDoublePrivate::valueChanged(double, QObject*)+0x4a
              mixxx`ControlDoublePrivate::set(double, QObject*)+0x8e
              mixxx`EngineVuMeter::process(float*, int)+0x1e7
              mixxx`EngineMaster::process(int)+0xaeb
              mixxx`SoundDevicePortAudio::callbackProcessClkRef(unsigned int, float*, float const*, PaStreamCallbackTimeInfo const*, unsigned long)+0x661
              mixxx`(anonymous namespace)::paV19CallbackClkRef(void const*, void*, unsigned long, PaStreamCallbackTimeInfo const*, unsigned long, void*)+0x23
              libportaudio.2.dylib`AdaptingOutputOnlyProcess+0xe7
              libportaudio.2.dylib`PaUtil_EndBufferProcessing+0x1c4
              libportaudio.2.dylib`AudioIOProc+0x392
              CoreAudio`AUConverterBase::RenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int)+0x2c5
              CoreAudio`AUBase::DoRenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, AUOutputElement*, unsigned int, AudioBufferList&)+0x9a
              CoreAudio`AUBase::DoRender(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int, AudioBufferList&)+0x1f8
              CoreAudio`AUHAL::AUIOProc(unsigned int, AudioTimeStamp const*, AudioBufferList const*, AudioTimeStamp const*, AudioBufferList*, AudioTimeStamp const*, void*)+0x6f2
              CoreAudio`HALC_ProxyIOContext::IOWorkLoop()+0x9e7
  syscall duration ns
           value ------------- Distribution ------------- count
            2048 | 0
            4096 |@@ 30
            8192 |@@@@@@@@ 111
           16384 |@@@@@@@@@@@@@@@@@@@@@@@@ 342
           32768 |@@@@@@ 78
           65536 | 3
          131072 | 0

              libsystem_kernel.dylib`__psynch_mutexwait+0xa
              libsystem_pthread.dylib`_pthread_mutex_lock_slow+0x12c
              CoreFoundation`CFRunLoopWakeUp+0x4b
              QtGui`QEventDispatcherMac::wakeUp()+0x30
              QtCore`QCoreApplication::postEvent(QObject*, QEvent*, int)+0x12f
              QtCore`QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+0x55a
              mixxx`ControlDoublePrivate::valueChanged(double, QObject*)+0x4a
              mixxx`ControlDoublePrivate::set(double, QObject*)+0x8e
              mixxx`EngineBuffer::updateIndicators(double, int)+0xc0
              mixxx`EngineMaster::processChannels(int)+0x6b3
              mixxx`EngineMaster::process(int)+0x135
              mixxx`SoundDevicePortAudio::callbackProcessClkRef(unsigned int, float*, float const*, PaStreamCallbackTimeInfo const*...

Read more...

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

              libsystem_kernel.dylib`__gettimeofday+0xa
              mixxx`EngineNetworkStream::getWriteExpected()+0x17
              mixxx`SoundDeviceNetwork::writeProcess()+0xd4
              mixxx`SoundManager::writeProcess()+0xb9
              mixxx`SoundDevicePortAudio::callbackProcessClkRef(unsigned int, float*, float const*, PaStreamCallbackTimeInfo const*, unsigned long)+0x751
              mixxx`(anonymous namespace)::paV19CallbackClkRef(void const*, void*, unsigned long, PaStreamCallbackTimeInfo const*, unsigned long, void*)+0x23
              libportaudio.2.dylib`AdaptingOutputOnlyProcess+0xe7
              libportaudio.2.dylib`PaUtil_EndBufferProcessing+0x1c4
              libportaudio.2.dylib`AudioIOProc+0x392
              CoreAudio`AUConverterBase::RenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int)+0x2c5
              CoreAudio`AUBase::DoRenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, AUOutputElement*, unsigned int, AudioBufferList&)+0x9a
              CoreAudio`AUBase::DoRender(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int, AudioBufferList&)+0x1f8
              CoreAudio`AUHAL::AUIOProc(unsigned int, AudioTimeStamp const*, AudioBufferList const*, AudioTimeStamp const*, AudioBufferList*, AudioTimeStamp const*, void*)+0x6f2
              CoreAudio`HALC_ProxyIOContext::IOWorkLoop()+0x9e7
              CoreAudio`HALC_ProxyIOContext::IOThreadEntry(void*)+0x58
              CoreAudio`HALB_IOThread::Entry(void*)+0x4b
              libsystem_pthread.dylib`_pthread_body+0x83
              libsystem_pthread.dylib`_pthread_body
              libsystem_pthread.dylib`thread_start+0xd
  syscall duration ns
           value ------------- Distribution ------------- count
            2048 | 0
            4096 |@@@@@@@@@@@@@@@@@@@@@@@ 160
            8192 |@@@@@@@@@@@@@@@@ 112
           16384 | 1
           32768 | 0

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

I didn't see anything in here that was particularly surprising -- these were all things we knew we were doing, but having ballpark numbers is nice.

Some initial thoughts:

* We may see some tail latency improvements from using tcmalloc given the cases where we ended up in malloc seemed quite expensive (up to 65us).

* ControlObject::set can cost 16us locking mutexes alone. Queued connections allocate memory too (which can also block). We really need to get COs out of the engine.

* SideChain writing costs ~8-16us just signaling the sidechain thread.

* Why is SoundDeviceNetwork open when no shoutcast stream is enabled? Do we need to be calling gettimeofday from the engine thread?

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

Here's my dtrace script:

HALC_IO*:::IOProc_Begin
/execname == "mixxx"/
{
  self->callback_tid = tid;
  self->callback_enter_ts = timestamp;
  self->callback_enter_vts = vtimestamp;
}

HALC_IO*:::IOProc_End
/execname == "mixxx" && self->callback_enter_ts/
{
  @[ustack(), "callback duration ns"] = quantize(timestamp - self->callback_enter_ts);
  @[ustack(), "callback on-cpu duration ns"] = quantize(vtimestamp - self->callback_enter_vts);
  self->callback_enter_ts = 0;
  self->callback_enter_vts = 0;
}

syscall:::entry
/execname == "mixxx" && tid == self->callback_tid/
{
  self->syscall_ts = timestamp;
}

syscall:::return
/execname == "mixxx" && tid == self->callback_tid && self->syscall_ts/
{
  @[ustack(), "syscall duration ns"] = quantize(timestamp - self->syscall_ts);
  self->syscall_ts = 0;
}

Revision history for this message
Daniel Schürmann (daschuer) wrote :

> * We may see some tail latency improvements from using tcmalloc given the cases where we ended up in malloc seemed quite expensive (up to 65us).

Does it mean we need to override the new() operator for some classes? How does it work together with precompiled qt libraries?

> * ControlObject::set can cost 16us locking mutexes alone. Queued connections allocate memory too (which can also block). We really need to get COs out of the engine.

Yes! I have already thought about it what will be a good approach, that is performant, but not requires a change in our business logic.

On Idea was to implement a new CO Proxy type that has value buffer for pending changes from the engine and a chain pointer that allows to chain all touched COs.

During the callback set() writes the value buffer and puts the CO on top of the linked list.
After the engine call, a new threads works though the fifo list and updates the underlying CO accordingly.

Unfortunately I am not sure if this really improves the performance, because the work is still there and the fifo should be empty before we can continue with the next engine call.

If we assume that we protect these threads from each other by a single mutex, we use actually more CPU, but we benefit from multi core cpus.

Maybe we find a way to make the chain of Engine COs lock free

> * Why is SoundDeviceNetwork open when no shoutcast stream is enabled?

There is no strong reason for it. It requires some work to enable it on demand though.

> * Do we need to be calling gettimeofday from the engine thread?

Yes, that is the main reason for having SoundDeviceNetwork, it runs at the network synced gettimeofday clock.

By the way, there is a Pending PR, that allows to run the whole engine at this clock to remove sync artifacts from the broadcast stream: https://github.com/mixxxdj/mixxx/pull/894

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

Taking the max of on-cpu vs on+off-cpu callback duration shows something of an upper bound (ok, sloppy math) for the amount of time the callback can sleep.

  callback on-cpu duration max ns 2447591
  callback duration max ns 4713387

Here is a histogram of the number of times that the callback thread blocks per callback (I put a dtrace probe on sched:::off-cpu and incremented a counter between HALC_IO*:::IOProc_Begin and HALC_IO*:::IOProc_End to get this metric.

This is playing 2 tracks at system reported latency of 13.5828ms for about 30 seconds.

  offcpu count
           value ------------- Distribution ------------- count
              -1 | 0
               0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 15659
               1 | 11
               2 | 7
               4 | 1
               8 | 0

Note that these power-of-2 histograms dtrace produces account an event to the smallest power of 2 that is less than or equal to the true number. So the true maximum here is somewhere between 4 and 7.

Revision history for this message
Swiftb0y (swiftb0y) wrote :

Mixxx now uses GitHub for bug tracking. This bug has been migrated to:
https://github.com/mixxxdj/mixxx/issues/8719

lock status: Metadata changes locked and limited to project staff
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.