add timings to AudioMixer

This commit is contained in:
Zach Pomerantz 2016-12-06 23:51:06 +00:00
parent 2a6e46aa0c
commit 132e9bd644
2 changed files with 96 additions and 23 deletions

View file

@ -260,6 +260,7 @@ void AudioMixer::sendStatsPacket() {
return; return;
} }
// general stats
statsObject["useDynamicJitterBuffers"] = _numStaticJitterFrames == -1; statsObject["useDynamicJitterBuffers"] = _numStaticJitterFrames == -1;
statsObject["trailing_sleep_percentage"] = _trailingSleepRatio * 100.0f; statsObject["trailing_sleep_percentage"] = _trailingSleepRatio * 100.0f;
statsObject["performance_throttling_ratio"] = _performanceThrottlingRatio; statsObject["performance_throttling_ratio"] = _performanceThrottlingRatio;
@ -267,16 +268,36 @@ void AudioMixer::sendStatsPacket() {
statsObject["avg_streams_per_frame"] = (float)_stats.sumStreams / (float)_numStatFrames; statsObject["avg_streams_per_frame"] = (float)_stats.sumStreams / (float)_numStatFrames;
statsObject["avg_listeners_per_frame"] = (float)_stats.sumListeners / (float)_numStatFrames; statsObject["avg_listeners_per_frame"] = (float)_stats.sumListeners / (float)_numStatFrames;
_sumMixTimesIndex = (_sumMixTimesIndex + 1) % MIX_TIMES_TRAILING_SECONDS; // timing stats
_sumMixTimesTrailing -= _sumMixTimesHistory[_sumMixTimesIndex]; QJsonObject timingStats;
_sumMixTimesHistory[_sumMixTimesIndex] = _sumMixTimes.count(); uint64_t timing, trailing;
_sumMixTimesTrailing += _sumMixTimesHistory[_sumMixTimesIndex];
statsObject["avg_us_per_frame"] = (qint64)(_sumMixTimes.count() / _numStatFrames); _sleepTiming.get(timing, trailing);
statsObject["avg_us_per_frames_trailing"] = timingStats["us_per_sleep"] = (qint64)(timing / _numStatFrames);
(qint64)((_sumMixTimesTrailing / MIX_TIMES_TRAILING_SECONDS) / _numStatFrames); timingStats["us_per_sleep_trailing"] = (qint64)(trailing / _numStatFrames);
_frameTiming.get(timing, trailing);
timingStats["us_per_frame"] = (qint64)(timing / _numStatFrames);
timingStats["us_per_frame_trailing"] = (qint64)(trailing / _numStatFrames);
_prepareTiming.get(timing, trailing);
timingStats["us_per_prepare"] = (qint64)(timing / _numStatFrames);
timingStats["us_per_prepare_trailing"] = (qint64)(trailing / _numStatFrames);
_mixTiming.get(timing, trailing);
timingStats["us_per_mix"] = (qint64)(timing / _numStatFrames);
timingStats["us_per_mix_trailing"] = (qint64)(trailing / _numStatFrames);
_eventsTiming.get(timing, trailing);
timingStats["us_per_events"] = (qint64)(timing / _numStatFrames);
timingStats["us_per_events_trailing"] = (qint64)(trailing / _numStatFrames);
// call it "avg_..." to keep it higher in the display, sorted alphabetically
statsObject["avg_timing_stats"] = timingStats;
// mix stats
QJsonObject mixStats; QJsonObject mixStats;
mixStats["%_hrtf_mixes"] = percentageForMixStats(_stats.hrtfRenders); mixStats["%_hrtf_mixes"] = percentageForMixStats(_stats.hrtfRenders);
mixStats["%_hrtf_silent_mixes"] = percentageForMixStats(_stats.hrtfSilentRenders); mixStats["%_hrtf_silent_mixes"] = percentageForMixStats(_stats.hrtfSilentRenders);
mixStats["%_hrtf_struggle_mixes"] = percentageForMixStats(_stats.hrtfStruggleRenders); mixStats["%_hrtf_struggle_mixes"] = percentageForMixStats(_stats.hrtfStruggleRenders);
@ -289,7 +310,6 @@ void AudioMixer::sendStatsPacket() {
statsObject["mix_stats"] = mixStats; statsObject["mix_stats"] = mixStats;
_numStatFrames = 0; _numStatFrames = 0;
_sumMixTimes = std::chrono::microseconds(0);
_stats.reset(); _stats.reset();
// add stats for each listerner // add stats for each listerner
@ -364,22 +384,30 @@ void AudioMixer::start() {
unsigned int frame = 1; unsigned int frame = 1;
while (!_isFinished) { while (!_isFinished) {
manageLoad(frameTimestamp, framesSinceManagement); {
auto timer = _sleepTiming.timer();
manageLoad(frameTimestamp, framesSinceManagement);
}
// start timing the frame auto timer = _frameTiming.timer();
auto startTime = p_high_resolution_clock::now();
// aquire the read-lock in a single thread, to avoid canonical rwlock undefined behaviors // aquire the read-lock in a single thread, to avoid canonical rwlock undefined behaviors
// node removal will acquire a write lock; // node removal will acquire a write lock;
// read locks (in slave threads) while a write lock is pending have undefined order in pthread // read locks (in slave threads) while a write lock is pending have undefined order in pthread
nodeList->algorithm([&](NodeList::const_iterator cbegin, NodeList::const_iterator cend) { nodeList->algorithm([&](NodeList::const_iterator cbegin, NodeList::const_iterator cend) {
// prepare frames; pop off any new audio from their streams // prepare frames; pop off any new audio from their streams
std::for_each(cbegin, cend, [&](const SharedNodePointer& node) { {
_stats.sumStreams += prepareFrame(node, frame); auto timer = _prepareTiming.timer();
}); std::for_each(cbegin, cend, [&](const SharedNodePointer& node) {
_stats.sumStreams += prepareFrame(node, frame);
});
}
// mix across slave threads // mix across slave threads
_slavePool.mix(cbegin, cend, frame); {
auto timer = _mixTiming.timer();
_slavePool.mix(cbegin, cend, frame);
}
}); });
// gather stats // gather stats
@ -388,14 +416,13 @@ void AudioMixer::start() {
slave.stats.reset(); slave.stats.reset();
}); });
// stop timing the frame
_sumMixTimes += std::chrono::duration_cast<std::chrono::microseconds>(p_high_resolution_clock::now() - startTime);
++frame; ++frame;
++_numStatFrames; ++_numStatFrames;
// play nice with qt event-looping // play nice with qt event-looping
{ {
auto timer = _eventsTiming.timer();
// since we're a while loop we need to yield to qt's event processing // since we're a while loop we need to yield to qt's event processing
QCoreApplication::processEvents(); QCoreApplication::processEvents();
@ -695,3 +722,28 @@ void AudioMixer::parseSettingsObject(const QJsonObject &settingsObject) {
} }
} }
} }
AudioMixer::Timer::Timing::Timing(uint64_t& sum) : _sum(sum) {
_timing = p_high_resolution_clock::now();
}
AudioMixer::Timer::Timing::~Timing() {
_sum += std::chrono::duration_cast<std::chrono::microseconds>(p_high_resolution_clock::now() - _timing).count();
}
void AudioMixer::Timer::get(uint64_t& timing, uint64_t& trailing) {
// update history
_index = (_index + 1) % TIMER_TRAILING_SECONDS;
uint64_t oldTiming = _history[_index];
_history[_index] = _sum;
// update trailing
_trailing -= oldTiming;
_trailing += _sum;
timing = _sum;
trailing = _trailing / TIMER_TRAILING_SECONDS;
// reset _sum;
_sum = 0;
}

View file

@ -90,11 +90,32 @@ private:
AudioMixerSlavePool _slavePool; AudioMixerSlavePool _slavePool;
static const int MIX_TIMES_TRAILING_SECONDS = 10; class Timer {
std::chrono::microseconds _sumMixTimes { 0 }; public:
uint64_t _sumMixTimesTrailing { 0 }; class Timing{
uint64_t _sumMixTimesHistory[MIX_TIMES_TRAILING_SECONDS] {}; public:
int _sumMixTimesIndex { 0 }; Timing(uint64_t& sum);
~Timing();
private:
p_high_resolution_clock::time_point _timing;
uint64_t& _sum;
};
Timing timer() { return Timing(_sum); }
void get(uint64_t& timing, uint64_t& trailing);
private:
static const int TIMER_TRAILING_SECONDS = 10;
uint64_t _sum { 0 };
uint64_t _trailing { 0 };
uint64_t _history[TIMER_TRAILING_SECONDS] {};
int _index { 0 };
};
Timer _sleepTiming;
Timer _frameTiming;
Timer _prepareTiming;
Timer _mixTiming;
Timer _eventsTiming;
static int _numStaticJitterFrames; // -1 denotes dynamic jitter buffering static int _numStaticJitterFrames; // -1 denotes dynamic jitter buffering
static float _noiseMutingThreshold; static float _noiseMutingThreshold;