From 04333cdc8d6a3c8e4a11835371e8ad13adf3f7f0 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 17 Feb 2015 16:23:03 -0800 Subject: Pull out FastCaptureDumpState and FastMixerDumpState Change-Id: I8e44dbfe02338622eb69193b234743b50f0dd79f --- services/audioflinger/Android.mk | 2 + services/audioflinger/FastCapture.cpp | 9 - services/audioflinger/FastCapture.h | 14 +- services/audioflinger/FastCaptureDumpState.cpp | 30 +++ services/audioflinger/FastCaptureDumpState.h | 40 ++++ services/audioflinger/FastMixer.cpp | 219 --------------------- services/audioflinger/FastMixerDumpState.cpp | 252 +++++++++++++++++++++++++ services/audioflinger/FastMixerDumpState.h | 2 + 8 files changed, 327 insertions(+), 241 deletions(-) create mode 100644 services/audioflinger/FastCaptureDumpState.cpp create mode 100644 services/audioflinger/FastCaptureDumpState.h create mode 100644 services/audioflinger/FastMixerDumpState.cpp (limited to 'services/audioflinger') diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk index f029333..642ff82 100644 --- a/services/audioflinger/Android.mk +++ b/services/audioflinger/Android.mk @@ -77,8 +77,10 @@ LOCAL_32_BIT_ONLY := true LOCAL_SRC_FILES += \ AudioWatchdog.cpp \ FastCapture.cpp \ + FastCaptureDumpState.cpp \ FastCaptureState.cpp \ FastMixer.cpp \ + FastMixerDumpState.cpp \ FastMixerState.cpp \ FastThread.cpp \ FastThreadDumpState.cpp \ diff --git a/services/audioflinger/FastCapture.cpp b/services/audioflinger/FastCapture.cpp index 0c9b976..1c4f670 100644 --- a/services/audioflinger/FastCapture.cpp +++ b/services/audioflinger/FastCapture.cpp @@ -210,13 +210,4 @@ void FastCapture::onWork() } } -FastCaptureDumpState::FastCaptureDumpState() : FastThreadDumpState(), - mReadSequence(0), mFramesRead(0), mReadErrors(0), mSampleRate(0), mFrameCount(0) -{ -} - -FastCaptureDumpState::~FastCaptureDumpState() -{ -} - } // namespace android diff --git a/services/audioflinger/FastCapture.h b/services/audioflinger/FastCapture.h index e61e026..da0fe2f 100644 --- a/services/audioflinger/FastCapture.h +++ b/services/audioflinger/FastCapture.h @@ -20,24 +20,12 @@ #include "FastThread.h" #include "StateQueue.h" #include "FastCaptureState.h" -#include "FastThreadDumpState.h" +#include "FastCaptureDumpState.h" namespace android { typedef StateQueue FastCaptureStateQueue; -struct FastCaptureDumpState : FastThreadDumpState { - FastCaptureDumpState(); - /*virtual*/ ~FastCaptureDumpState(); - - // FIXME by renaming, could pull up many of these to FastThreadDumpState - uint32_t mReadSequence; // incremented before and after each read() - uint32_t mFramesRead; // total number of frames read successfully - uint32_t mReadErrors; // total number of read() errors - uint32_t mSampleRate; - size_t mFrameCount; -}; - class FastCapture : public FastThread { public: diff --git a/services/audioflinger/FastCaptureDumpState.cpp b/services/audioflinger/FastCaptureDumpState.cpp new file mode 100644 index 0000000..00f8da0 --- /dev/null +++ b/services/audioflinger/FastCaptureDumpState.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "FastCaptureDumpState.h" + +namespace android { + +FastCaptureDumpState::FastCaptureDumpState() : FastThreadDumpState(), + mReadSequence(0), mFramesRead(0), mReadErrors(0), mSampleRate(0), mFrameCount(0) +{ +} + +FastCaptureDumpState::~FastCaptureDumpState() +{ +} + +} // android diff --git a/services/audioflinger/FastCaptureDumpState.h b/services/audioflinger/FastCaptureDumpState.h new file mode 100644 index 0000000..ee99099 --- /dev/null +++ b/services/audioflinger/FastCaptureDumpState.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_AUDIO_FAST_CAPTURE_DUMP_STATE_H +#define ANDROID_AUDIO_FAST_CAPTURE_DUMP_STATE_H + +#include +#include "Configuration.h" +#include "FastThreadDumpState.h" + +namespace android { + +struct FastCaptureDumpState : FastThreadDumpState { + FastCaptureDumpState(); + /*virtual*/ ~FastCaptureDumpState(); + + // FIXME by renaming, could pull up many of these to FastThreadDumpState + uint32_t mReadSequence; // incremented before and after each read() + uint32_t mFramesRead; // total number of frames read successfully + uint32_t mReadErrors; // total number of read() errors + uint32_t mSampleRate; + size_t mFrameCount; +}; + +} // android + +#endif // ANDROID_AUDIO_FAST_CAPTURE_DUMP_STATE_H diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp index 141a79e..8f05ef0 100644 --- a/services/audioflinger/FastMixer.cpp +++ b/services/audioflinger/FastMixer.cpp @@ -456,223 +456,4 @@ void FastMixer::onWork() } } -FastMixerDumpState::FastMixerDumpState( -#ifdef FAST_MIXER_STATISTICS - uint32_t samplingN -#endif - ) : FastThreadDumpState(), - mWriteSequence(0), mFramesWritten(0), - mNumTracks(0), mWriteErrors(0), - mSampleRate(0), mFrameCount(0), - mTrackMask(0) -{ -#ifdef FAST_MIXER_STATISTICS - increaseSamplingN(samplingN); -#endif -} - -#ifdef FAST_MIXER_STATISTICS -void FastMixerDumpState::increaseSamplingN(uint32_t samplingN) -{ - if (samplingN <= mSamplingN || samplingN > kSamplingN || roundup(samplingN) != samplingN) { - return; - } - uint32_t additional = samplingN - mSamplingN; - // sample arrays aren't accessed atomically with respect to the bounds, - // so clearing reduces chance for dumpsys to read random uninitialized samples - memset(&mMonotonicNs[mSamplingN], 0, sizeof(mMonotonicNs[0]) * additional); - memset(&mLoadNs[mSamplingN], 0, sizeof(mLoadNs[0]) * additional); -#ifdef CPU_FREQUENCY_STATISTICS - memset(&mCpukHz[mSamplingN], 0, sizeof(mCpukHz[0]) * additional); -#endif - mSamplingN = samplingN; -} -#endif - -FastMixerDumpState::~FastMixerDumpState() -{ -} - -// helper function called by qsort() -static int compare_uint32_t(const void *pa, const void *pb) -{ - uint32_t a = *(const uint32_t *)pa; - uint32_t b = *(const uint32_t *)pb; - if (a < b) { - return -1; - } else if (a > b) { - return 1; - } else { - return 0; - } -} - -void FastMixerDumpState::dump(int fd) const -{ - if (mCommand == FastMixerState::INITIAL) { - dprintf(fd, " FastMixer not initialized\n"); - return; - } -#define COMMAND_MAX 32 - char string[COMMAND_MAX]; - switch (mCommand) { - case FastMixerState::INITIAL: - strcpy(string, "INITIAL"); - break; - case FastMixerState::HOT_IDLE: - strcpy(string, "HOT_IDLE"); - break; - case FastMixerState::COLD_IDLE: - strcpy(string, "COLD_IDLE"); - break; - case FastMixerState::EXIT: - strcpy(string, "EXIT"); - break; - case FastMixerState::MIX: - strcpy(string, "MIX"); - break; - case FastMixerState::WRITE: - strcpy(string, "WRITE"); - break; - case FastMixerState::MIX_WRITE: - strcpy(string, "MIX_WRITE"); - break; - default: - snprintf(string, COMMAND_MAX, "%d", mCommand); - break; - } - double measuredWarmupMs = (mMeasuredWarmupTs.tv_sec * 1000.0) + - (mMeasuredWarmupTs.tv_nsec / 1000000.0); - double mixPeriodSec = (double) mFrameCount / (double) mSampleRate; - dprintf(fd, " FastMixer command=%s writeSequence=%u framesWritten=%u\n" - " numTracks=%u writeErrors=%u underruns=%u overruns=%u\n" - " sampleRate=%u frameCount=%zu measuredWarmup=%.3g ms, warmupCycles=%u\n" - " mixPeriod=%.2f ms\n", - string, mWriteSequence, mFramesWritten, - mNumTracks, mWriteErrors, mUnderruns, mOverruns, - mSampleRate, mFrameCount, measuredWarmupMs, mWarmupCycles, - mixPeriodSec * 1e3); -#ifdef FAST_MIXER_STATISTICS - // find the interval of valid samples - uint32_t bounds = mBounds; - uint32_t newestOpen = bounds & 0xFFFF; - uint32_t oldestClosed = bounds >> 16; - uint32_t n = (newestOpen - oldestClosed) & 0xFFFF; - if (n > mSamplingN) { - ALOGE("too many samples %u", n); - n = mSamplingN; - } - // statistics for monotonic (wall clock) time, thread raw CPU load in time, CPU clock frequency, - // and adjusted CPU load in MHz normalized for CPU clock frequency - CentralTendencyStatistics wall, loadNs; -#ifdef CPU_FREQUENCY_STATISTICS - CentralTendencyStatistics kHz, loadMHz; - uint32_t previousCpukHz = 0; -#endif - // Assuming a normal distribution for cycle times, three standard deviations on either side of - // the mean account for 99.73% of the population. So if we take each tail to be 1/1000 of the - // sample set, we get 99.8% combined, or close to three standard deviations. - static const uint32_t kTailDenominator = 1000; - uint32_t *tail = n >= kTailDenominator ? new uint32_t[n] : NULL; - // loop over all the samples - for (uint32_t j = 0; j < n; ++j) { - size_t i = oldestClosed++ & (mSamplingN - 1); - uint32_t wallNs = mMonotonicNs[i]; - if (tail != NULL) { - tail[j] = wallNs; - } - wall.sample(wallNs); - uint32_t sampleLoadNs = mLoadNs[i]; - loadNs.sample(sampleLoadNs); -#ifdef CPU_FREQUENCY_STATISTICS - uint32_t sampleCpukHz = mCpukHz[i]; - // skip bad kHz samples - if ((sampleCpukHz & ~0xF) != 0) { - kHz.sample(sampleCpukHz >> 4); - if (sampleCpukHz == previousCpukHz) { - double megacycles = (double) sampleLoadNs * (double) (sampleCpukHz >> 4) * 1e-12; - double adjMHz = megacycles / mixPeriodSec; // _not_ wallNs * 1e9 - loadMHz.sample(adjMHz); - } - } - previousCpukHz = sampleCpukHz; -#endif - } - if (n) { - dprintf(fd, " Simple moving statistics over last %.1f seconds:\n", - wall.n() * mixPeriodSec); - dprintf(fd, " wall clock time in ms per mix cycle:\n" - " mean=%.2f min=%.2f max=%.2f stddev=%.2f\n", - wall.mean()*1e-6, wall.minimum()*1e-6, wall.maximum()*1e-6, - wall.stddev()*1e-6); - dprintf(fd, " raw CPU load in us per mix cycle:\n" - " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n", - loadNs.mean()*1e-3, loadNs.minimum()*1e-3, loadNs.maximum()*1e-3, - loadNs.stddev()*1e-3); - } else { - dprintf(fd, " No FastMixer statistics available currently\n"); - } -#ifdef CPU_FREQUENCY_STATISTICS - dprintf(fd, " CPU clock frequency in MHz:\n" - " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n", - kHz.mean()*1e-3, kHz.minimum()*1e-3, kHz.maximum()*1e-3, kHz.stddev()*1e-3); - dprintf(fd, " adjusted CPU load in MHz (i.e. normalized for CPU clock frequency):\n" - " mean=%.1f min=%.1f max=%.1f stddev=%.1f\n", - loadMHz.mean(), loadMHz.minimum(), loadMHz.maximum(), loadMHz.stddev()); -#endif - if (tail != NULL) { - qsort(tail, n, sizeof(uint32_t), compare_uint32_t); - // assume same number of tail samples on each side, left and right - uint32_t count = n / kTailDenominator; - CentralTendencyStatistics left, right; - for (uint32_t i = 0; i < count; ++i) { - left.sample(tail[i]); - right.sample(tail[n - (i + 1)]); - } - dprintf(fd, " Distribution of mix cycle times in ms for the tails " - "(> ~3 stddev outliers):\n" - " left tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n" - " right tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n", - left.mean()*1e-6, left.minimum()*1e-6, left.maximum()*1e-6, left.stddev()*1e-6, - right.mean()*1e-6, right.minimum()*1e-6, right.maximum()*1e-6, - right.stddev()*1e-6); - delete[] tail; - } -#endif - // The active track mask and track states are updated non-atomically. - // So if we relied on isActive to decide whether to display, - // then we might display an obsolete track or omit an active track. - // Instead we always display all tracks, with an indication - // of whether we think the track is active. - uint32_t trackMask = mTrackMask; - dprintf(fd, " Fast tracks: kMaxFastTracks=%u activeMask=%#x\n", - FastMixerState::kMaxFastTracks, trackMask); - dprintf(fd, " Index Active Full Partial Empty Recent Ready\n"); - for (uint32_t i = 0; i < FastMixerState::kMaxFastTracks; ++i, trackMask >>= 1) { - bool isActive = trackMask & 1; - const FastTrackDump *ftDump = &mTracks[i]; - const FastTrackUnderruns& underruns = ftDump->mUnderruns; - const char *mostRecent; - switch (underruns.mBitFields.mMostRecent) { - case UNDERRUN_FULL: - mostRecent = "full"; - break; - case UNDERRUN_PARTIAL: - mostRecent = "partial"; - break; - case UNDERRUN_EMPTY: - mostRecent = "empty"; - break; - default: - mostRecent = "?"; - break; - } - dprintf(fd, " %5u %6s %4u %7u %5u %7s %5zu\n", i, isActive ? "yes" : "no", - (underruns.mBitFields.mFull) & UNDERRUN_MASK, - (underruns.mBitFields.mPartial) & UNDERRUN_MASK, - (underruns.mBitFields.mEmpty) & UNDERRUN_MASK, - mostRecent, ftDump->mFramesReady); - } -} - } // namespace android diff --git a/services/audioflinger/FastMixerDumpState.cpp b/services/audioflinger/FastMixerDumpState.cpp new file mode 100644 index 0000000..0ddd908 --- /dev/null +++ b/services/audioflinger/FastMixerDumpState.cpp @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "FastMixerDumpState" +//#define LOG_NDEBUG 0 + +#include "Configuration.h" +#ifdef FAST_MIXER_STATISTICS +#include +#ifdef CPU_FREQUENCY_STATISTICS +#include +#endif +#endif +#include +#include +#include "FastMixerDumpState.h" + +namespace android { + +FastMixerDumpState::FastMixerDumpState( +#ifdef FAST_MIXER_STATISTICS + uint32_t samplingN +#endif + ) : FastThreadDumpState(), + mWriteSequence(0), mFramesWritten(0), + mNumTracks(0), mWriteErrors(0), + mSampleRate(0), mFrameCount(0), + mTrackMask(0) +{ +#ifdef FAST_MIXER_STATISTICS + increaseSamplingN(samplingN); +#endif +} + +#ifdef FAST_MIXER_STATISTICS +void FastMixerDumpState::increaseSamplingN(uint32_t samplingN) +{ + if (samplingN <= mSamplingN || samplingN > kSamplingN || roundup(samplingN) != samplingN) { + return; + } + uint32_t additional = samplingN - mSamplingN; + // sample arrays aren't accessed atomically with respect to the bounds, + // so clearing reduces chance for dumpsys to read random uninitialized samples + memset(&mMonotonicNs[mSamplingN], 0, sizeof(mMonotonicNs[0]) * additional); + memset(&mLoadNs[mSamplingN], 0, sizeof(mLoadNs[0]) * additional); +#ifdef CPU_FREQUENCY_STATISTICS + memset(&mCpukHz[mSamplingN], 0, sizeof(mCpukHz[0]) * additional); +#endif + mSamplingN = samplingN; +} +#endif + +FastMixerDumpState::~FastMixerDumpState() +{ +} + +// helper function called by qsort() +static int compare_uint32_t(const void *pa, const void *pb) +{ + uint32_t a = *(const uint32_t *)pa; + uint32_t b = *(const uint32_t *)pb; + if (a < b) { + return -1; + } else if (a > b) { + return 1; + } else { + return 0; + } +} + +void FastMixerDumpState::dump(int fd) const +{ + if (mCommand == FastMixerState::INITIAL) { + dprintf(fd, " FastMixer not initialized\n"); + return; + } +#define COMMAND_MAX 32 + char string[COMMAND_MAX]; + switch (mCommand) { + case FastMixerState::INITIAL: + strcpy(string, "INITIAL"); + break; + case FastMixerState::HOT_IDLE: + strcpy(string, "HOT_IDLE"); + break; + case FastMixerState::COLD_IDLE: + strcpy(string, "COLD_IDLE"); + break; + case FastMixerState::EXIT: + strcpy(string, "EXIT"); + break; + case FastMixerState::MIX: + strcpy(string, "MIX"); + break; + case FastMixerState::WRITE: + strcpy(string, "WRITE"); + break; + case FastMixerState::MIX_WRITE: + strcpy(string, "MIX_WRITE"); + break; + default: + snprintf(string, COMMAND_MAX, "%d", mCommand); + break; + } + double measuredWarmupMs = (mMeasuredWarmupTs.tv_sec * 1000.0) + + (mMeasuredWarmupTs.tv_nsec / 1000000.0); + double mixPeriodSec = (double) mFrameCount / (double) mSampleRate; + dprintf(fd, " FastMixer command=%s writeSequence=%u framesWritten=%u\n" + " numTracks=%u writeErrors=%u underruns=%u overruns=%u\n" + " sampleRate=%u frameCount=%zu measuredWarmup=%.3g ms, warmupCycles=%u\n" + " mixPeriod=%.2f ms\n", + string, mWriteSequence, mFramesWritten, + mNumTracks, mWriteErrors, mUnderruns, mOverruns, + mSampleRate, mFrameCount, measuredWarmupMs, mWarmupCycles, + mixPeriodSec * 1e3); +#ifdef FAST_MIXER_STATISTICS + // find the interval of valid samples + uint32_t bounds = mBounds; + uint32_t newestOpen = bounds & 0xFFFF; + uint32_t oldestClosed = bounds >> 16; + uint32_t n = (newestOpen - oldestClosed) & 0xFFFF; + if (n > mSamplingN) { + ALOGE("too many samples %u", n); + n = mSamplingN; + } + // statistics for monotonic (wall clock) time, thread raw CPU load in time, CPU clock frequency, + // and adjusted CPU load in MHz normalized for CPU clock frequency + CentralTendencyStatistics wall, loadNs; +#ifdef CPU_FREQUENCY_STATISTICS + CentralTendencyStatistics kHz, loadMHz; + uint32_t previousCpukHz = 0; +#endif + // Assuming a normal distribution for cycle times, three standard deviations on either side of + // the mean account for 99.73% of the population. So if we take each tail to be 1/1000 of the + // sample set, we get 99.8% combined, or close to three standard deviations. + static const uint32_t kTailDenominator = 1000; + uint32_t *tail = n >= kTailDenominator ? new uint32_t[n] : NULL; + // loop over all the samples + for (uint32_t j = 0; j < n; ++j) { + size_t i = oldestClosed++ & (mSamplingN - 1); + uint32_t wallNs = mMonotonicNs[i]; + if (tail != NULL) { + tail[j] = wallNs; + } + wall.sample(wallNs); + uint32_t sampleLoadNs = mLoadNs[i]; + loadNs.sample(sampleLoadNs); +#ifdef CPU_FREQUENCY_STATISTICS + uint32_t sampleCpukHz = mCpukHz[i]; + // skip bad kHz samples + if ((sampleCpukHz & ~0xF) != 0) { + kHz.sample(sampleCpukHz >> 4); + if (sampleCpukHz == previousCpukHz) { + double megacycles = (double) sampleLoadNs * (double) (sampleCpukHz >> 4) * 1e-12; + double adjMHz = megacycles / mixPeriodSec; // _not_ wallNs * 1e9 + loadMHz.sample(adjMHz); + } + } + previousCpukHz = sampleCpukHz; +#endif + } + if (n) { + dprintf(fd, " Simple moving statistics over last %.1f seconds:\n", + wall.n() * mixPeriodSec); + dprintf(fd, " wall clock time in ms per mix cycle:\n" + " mean=%.2f min=%.2f max=%.2f stddev=%.2f\n", + wall.mean()*1e-6, wall.minimum()*1e-6, wall.maximum()*1e-6, + wall.stddev()*1e-6); + dprintf(fd, " raw CPU load in us per mix cycle:\n" + " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n", + loadNs.mean()*1e-3, loadNs.minimum()*1e-3, loadNs.maximum()*1e-3, + loadNs.stddev()*1e-3); + } else { + dprintf(fd, " No FastMixer statistics available currently\n"); + } +#ifdef CPU_FREQUENCY_STATISTICS + dprintf(fd, " CPU clock frequency in MHz:\n" + " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n", + kHz.mean()*1e-3, kHz.minimum()*1e-3, kHz.maximum()*1e-3, kHz.stddev()*1e-3); + dprintf(fd, " adjusted CPU load in MHz (i.e. normalized for CPU clock frequency):\n" + " mean=%.1f min=%.1f max=%.1f stddev=%.1f\n", + loadMHz.mean(), loadMHz.minimum(), loadMHz.maximum(), loadMHz.stddev()); +#endif + if (tail != NULL) { + qsort(tail, n, sizeof(uint32_t), compare_uint32_t); + // assume same number of tail samples on each side, left and right + uint32_t count = n / kTailDenominator; + CentralTendencyStatistics left, right; + for (uint32_t i = 0; i < count; ++i) { + left.sample(tail[i]); + right.sample(tail[n - (i + 1)]); + } + dprintf(fd, " Distribution of mix cycle times in ms for the tails " + "(> ~3 stddev outliers):\n" + " left tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n" + " right tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n", + left.mean()*1e-6, left.minimum()*1e-6, left.maximum()*1e-6, left.stddev()*1e-6, + right.mean()*1e-6, right.minimum()*1e-6, right.maximum()*1e-6, + right.stddev()*1e-6); + delete[] tail; + } +#endif + // The active track mask and track states are updated non-atomically. + // So if we relied on isActive to decide whether to display, + // then we might display an obsolete track or omit an active track. + // Instead we always display all tracks, with an indication + // of whether we think the track is active. + uint32_t trackMask = mTrackMask; + dprintf(fd, " Fast tracks: kMaxFastTracks=%u activeMask=%#x\n", + FastMixerState::kMaxFastTracks, trackMask); + dprintf(fd, " Index Active Full Partial Empty Recent Ready\n"); + for (uint32_t i = 0; i < FastMixerState::kMaxFastTracks; ++i, trackMask >>= 1) { + bool isActive = trackMask & 1; + const FastTrackDump *ftDump = &mTracks[i]; + const FastTrackUnderruns& underruns = ftDump->mUnderruns; + const char *mostRecent; + switch (underruns.mBitFields.mMostRecent) { + case UNDERRUN_FULL: + mostRecent = "full"; + break; + case UNDERRUN_PARTIAL: + mostRecent = "partial"; + break; + case UNDERRUN_EMPTY: + mostRecent = "empty"; + break; + default: + mostRecent = "?"; + break; + } + dprintf(fd, " %5u %6s %4u %7u %5u %7s %5zu\n", i, isActive ? "yes" : "no", + (underruns.mBitFields.mFull) & UNDERRUN_MASK, + (underruns.mBitFields.mPartial) & UNDERRUN_MASK, + (underruns.mBitFields.mEmpty) & UNDERRUN_MASK, + mostRecent, ftDump->mFramesReady); + } +} + +} // android diff --git a/services/audioflinger/FastMixerDumpState.h b/services/audioflinger/FastMixerDumpState.h index 1ae191c..f8354dd 100644 --- a/services/audioflinger/FastMixerDumpState.h +++ b/services/audioflinger/FastMixerDumpState.h @@ -17,8 +17,10 @@ #ifndef ANDROID_AUDIO_FAST_MIXER_DUMP_STATE_H #define ANDROID_AUDIO_FAST_MIXER_DUMP_STATE_H +#include #include "Configuration.h" #include "FastThreadDumpState.h" +#include "FastMixerState.h" namespace android { -- cgit v1.1