Loading services/audioflinger/Android.mk +3 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,9 @@ LOCAL_SRC_FILES:= \ LOCAL_SRC_FILES += StateQueue.cpp # uncomment for debugging timing problems related to StateQueue::push() LOCAL_CFLAGS += -DSTATE_QUEUE_DUMP LOCAL_C_INCLUDES := \ $(call include-path-for, audio-effects) \ $(call include-path-for, audio-utils) Loading services/audioflinger/AudioFlinger.cpp +12 −0 Original line number Diff line number Diff line Loading @@ -2255,6 +2255,10 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud // create fast mixer and configure it initially with just one fast track for our submix mFastMixer = new FastMixer(); FastMixerStateQueue *sq = mFastMixer->sq(); #ifdef STATE_QUEUE_DUMP sq->setObserverDump(&mStateQueueObserverDump); sq->setMutatorDump(&mStateQueueMutatorDump); #endif FastMixerState *state = sq->begin(); FastTrack *fastTrack = &state->mFastTracks[0]; // wrap the source side of the MonoPipe to make it an AudioBufferProvider Loading Loading @@ -3480,6 +3484,14 @@ status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16> FastMixerDumpState copy = mFastMixerDumpState; copy.dump(fd); #ifdef STATE_QUEUE_DUMP // Similar for state queue StateQueueObserverDump observerCopy = mStateQueueObserverDump; observerCopy.dump(fd); StateQueueMutatorDump mutatorCopy = mStateQueueMutatorDump; mutatorCopy.dump(fd); #endif // Write the tee output to a .wav file NBAIO_Source *teeSource = mTeeSource.get(); if (teeSource != NULL) { Loading services/audioflinger/AudioFlinger.h +4 −0 Original line number Diff line number Diff line Loading @@ -1169,6 +1169,10 @@ public: // contents are not guaranteed to be consistent, no locks required FastMixerDumpState mFastMixerDumpState; #ifdef STATE_QUEUE_DUMP StateQueueObserverDump mStateQueueObserverDump; StateQueueMutatorDump mStateQueueMutatorDump; #endif // accessible only within the threadLoop(), no locks required // mFastMixer->sq() // for mutating and pushing state Loading services/audioflinger/StateQueue.cpp +57 −0 Original line number Diff line number Diff line Loading @@ -24,12 +24,28 @@ namespace android { #ifdef STATE_QUEUE_DUMP void StateQueueObserverDump::dump(int fd) { fdprintf(fd, "State queue observer: stateChanges=%u\n", mStateChanges); } void StateQueueMutatorDump::dump(int fd) { fdprintf(fd, "State queue mutator: pushDirty=%u pushAck=%u blockedSequence=%u\n", mPushDirty, mPushAck, mBlockedSequence); } #endif // Constructor and destructor template<typename T> StateQueue<T>::StateQueue() : mNext(NULL), mAck(NULL), mCurrent(NULL), mMutating(&mStates[0]), mExpecting(NULL), mInMutation(false), mIsDirty(false), mIsInitialized(false) #ifdef STATE_QUEUE_DUMP , mObserverDump(&mObserverDummyDump), mMutatorDump(&mMutatorDummyDump) #endif { } Loading @@ -45,6 +61,9 @@ template<typename T> const T* StateQueue<T>::poll() if (next != mCurrent) { mAck = next; // no additional barrier needed mCurrent = next; #ifdef STATE_QUEUE_DUMP mObserverDump->mStateChanges++; #endif } return next; } Loading Loading @@ -77,10 +96,23 @@ template<typename T> bool StateQueue<T>::push(StateQueue<T>::block_t block) ALOG_ASSERT(!mInMutation, "push() called when in a mutation"); #ifdef STATE_QUEUE_DUMP if (block == BLOCK_UNTIL_ACKED) { mMutatorDump->mPushAck++; } #endif if (mIsDirty) { #ifdef STATE_QUEUE_DUMP mMutatorDump->mPushDirty++; #endif // wait for prior push to be acknowledged if (mExpecting != NULL) { #ifdef STATE_QUEUE_DUMP unsigned count = 0; #endif for (;;) { const T *ack = (const T *) mAck; // no additional barrier needed if (ack == mExpecting) { Loading @@ -91,8 +123,19 @@ template<typename T> bool StateQueue<T>::push(StateQueue<T>::block_t block) if (block == BLOCK_NEVER) { return false; } #ifdef STATE_QUEUE_DUMP if (count == 1) { mMutatorDump->mBlockedSequence++; } ++count; #endif nanosleep(&req, NULL); } #ifdef STATE_QUEUE_DUMP if (count > 1) { mMutatorDump->mBlockedSequence++; } #endif } // publish Loading @@ -111,14 +154,28 @@ template<typename T> bool StateQueue<T>::push(StateQueue<T>::block_t block) // optionally wait for this push or a prior push to be acknowledged if (block == BLOCK_UNTIL_ACKED) { if (mExpecting != NULL) { #ifdef STATE_QUEUE_DUMP unsigned count = 0; #endif for (;;) { const T *ack = (const T *) mAck; // no additional barrier needed if (ack == mExpecting) { mExpecting = NULL; break; } #ifdef STATE_QUEUE_DUMP if (count == 1) { mMutatorDump->mBlockedSequence++; } ++count; #endif nanosleep(&req, NULL); } #ifdef STATE_QUEUE_DUMP if (count > 1) { mMutatorDump->mBlockedSequence++; } #endif } } Loading services/audioflinger/StateQueue.h +45 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,34 @@ namespace android { #ifdef STATE_QUEUE_DUMP // The StateQueueObserverDump and StateQueueMutatorDump keep // a cache of StateQueue statistics that can be logged by dumpsys. // Each individual native word-sized field is accessed atomically. But the // overall structure is non-atomic, that is there may be an inconsistency between fields. // No barriers or locks are used for either writing or reading. // Only POD types are permitted, and the contents shouldn't be trusted (i.e. do range checks). // It has a different lifetime than the StateQueue, and so it can't be a member of StateQueue. struct StateQueueObserverDump { StateQueueObserverDump() : mStateChanges(0) { } /*virtual*/ ~StateQueueObserverDump() { } unsigned mStateChanges; // incremented each time poll() detects a state change void dump(int fd); }; struct StateQueueMutatorDump { StateQueueMutatorDump() : mPushDirty(0), mPushAck(0), mBlockedSequence(0) { } /*virtual*/ ~StateQueueMutatorDump() { } unsigned mPushDirty; // incremented each time push() is called with a dirty state unsigned mPushAck; // incremented each time push(BLOCK_UNTIL_ACKED) is called unsigned mBlockedSequence; // incremented before and after each time that push() // blocks for more than one PUSH_BLOCK_ACK_NS; // if odd, then mutator is currently blocked inside push() void dump(int fd); }; #endif // manages a FIFO queue of states template<typename T> class StateQueue { Loading Loading @@ -69,6 +97,16 @@ public: // Return whether the current state is dirty (modified and not pushed). bool isDirty() const { return mIsDirty; } #ifdef STATE_QUEUE_DUMP // Register location of observer dump area void setObserverDump(StateQueueObserverDump *dump) { mObserverDump = dump != NULL ? dump : &mObserverDummyDump; } // Register location of mutator dump area void setMutatorDump(StateQueueMutatorDump *dump) { mMutatorDump = dump != NULL ? dump : &mMutatorDummyDump; } #endif private: static const unsigned kN = 4; // values != 4 are not supported by this code T mStates[kN]; // written by mutator, read by observer Loading @@ -87,6 +125,13 @@ private: bool mIsDirty; // whether mutating state has been modified since last push bool mIsInitialized; // whether mutating state has been initialized yet #ifdef STATE_QUEUE_DUMP StateQueueObserverDump mObserverDummyDump; // default area for observer dump if not set StateQueueObserverDump* mObserverDump; // pointer to active observer dump, always non-NULL StateQueueMutatorDump mMutatorDummyDump; // default area for mutator dump if not set StateQueueMutatorDump* mMutatorDump; // pointer to active mutator dump, always non-NULL #endif }; // class StateQueue } // namespace android Loading Loading
services/audioflinger/Android.mk +3 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,9 @@ LOCAL_SRC_FILES:= \ LOCAL_SRC_FILES += StateQueue.cpp # uncomment for debugging timing problems related to StateQueue::push() LOCAL_CFLAGS += -DSTATE_QUEUE_DUMP LOCAL_C_INCLUDES := \ $(call include-path-for, audio-effects) \ $(call include-path-for, audio-utils) Loading
services/audioflinger/AudioFlinger.cpp +12 −0 Original line number Diff line number Diff line Loading @@ -2255,6 +2255,10 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud // create fast mixer and configure it initially with just one fast track for our submix mFastMixer = new FastMixer(); FastMixerStateQueue *sq = mFastMixer->sq(); #ifdef STATE_QUEUE_DUMP sq->setObserverDump(&mStateQueueObserverDump); sq->setMutatorDump(&mStateQueueMutatorDump); #endif FastMixerState *state = sq->begin(); FastTrack *fastTrack = &state->mFastTracks[0]; // wrap the source side of the MonoPipe to make it an AudioBufferProvider Loading Loading @@ -3480,6 +3484,14 @@ status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16> FastMixerDumpState copy = mFastMixerDumpState; copy.dump(fd); #ifdef STATE_QUEUE_DUMP // Similar for state queue StateQueueObserverDump observerCopy = mStateQueueObserverDump; observerCopy.dump(fd); StateQueueMutatorDump mutatorCopy = mStateQueueMutatorDump; mutatorCopy.dump(fd); #endif // Write the tee output to a .wav file NBAIO_Source *teeSource = mTeeSource.get(); if (teeSource != NULL) { Loading
services/audioflinger/AudioFlinger.h +4 −0 Original line number Diff line number Diff line Loading @@ -1169,6 +1169,10 @@ public: // contents are not guaranteed to be consistent, no locks required FastMixerDumpState mFastMixerDumpState; #ifdef STATE_QUEUE_DUMP StateQueueObserverDump mStateQueueObserverDump; StateQueueMutatorDump mStateQueueMutatorDump; #endif // accessible only within the threadLoop(), no locks required // mFastMixer->sq() // for mutating and pushing state Loading
services/audioflinger/StateQueue.cpp +57 −0 Original line number Diff line number Diff line Loading @@ -24,12 +24,28 @@ namespace android { #ifdef STATE_QUEUE_DUMP void StateQueueObserverDump::dump(int fd) { fdprintf(fd, "State queue observer: stateChanges=%u\n", mStateChanges); } void StateQueueMutatorDump::dump(int fd) { fdprintf(fd, "State queue mutator: pushDirty=%u pushAck=%u blockedSequence=%u\n", mPushDirty, mPushAck, mBlockedSequence); } #endif // Constructor and destructor template<typename T> StateQueue<T>::StateQueue() : mNext(NULL), mAck(NULL), mCurrent(NULL), mMutating(&mStates[0]), mExpecting(NULL), mInMutation(false), mIsDirty(false), mIsInitialized(false) #ifdef STATE_QUEUE_DUMP , mObserverDump(&mObserverDummyDump), mMutatorDump(&mMutatorDummyDump) #endif { } Loading @@ -45,6 +61,9 @@ template<typename T> const T* StateQueue<T>::poll() if (next != mCurrent) { mAck = next; // no additional barrier needed mCurrent = next; #ifdef STATE_QUEUE_DUMP mObserverDump->mStateChanges++; #endif } return next; } Loading Loading @@ -77,10 +96,23 @@ template<typename T> bool StateQueue<T>::push(StateQueue<T>::block_t block) ALOG_ASSERT(!mInMutation, "push() called when in a mutation"); #ifdef STATE_QUEUE_DUMP if (block == BLOCK_UNTIL_ACKED) { mMutatorDump->mPushAck++; } #endif if (mIsDirty) { #ifdef STATE_QUEUE_DUMP mMutatorDump->mPushDirty++; #endif // wait for prior push to be acknowledged if (mExpecting != NULL) { #ifdef STATE_QUEUE_DUMP unsigned count = 0; #endif for (;;) { const T *ack = (const T *) mAck; // no additional barrier needed if (ack == mExpecting) { Loading @@ -91,8 +123,19 @@ template<typename T> bool StateQueue<T>::push(StateQueue<T>::block_t block) if (block == BLOCK_NEVER) { return false; } #ifdef STATE_QUEUE_DUMP if (count == 1) { mMutatorDump->mBlockedSequence++; } ++count; #endif nanosleep(&req, NULL); } #ifdef STATE_QUEUE_DUMP if (count > 1) { mMutatorDump->mBlockedSequence++; } #endif } // publish Loading @@ -111,14 +154,28 @@ template<typename T> bool StateQueue<T>::push(StateQueue<T>::block_t block) // optionally wait for this push or a prior push to be acknowledged if (block == BLOCK_UNTIL_ACKED) { if (mExpecting != NULL) { #ifdef STATE_QUEUE_DUMP unsigned count = 0; #endif for (;;) { const T *ack = (const T *) mAck; // no additional barrier needed if (ack == mExpecting) { mExpecting = NULL; break; } #ifdef STATE_QUEUE_DUMP if (count == 1) { mMutatorDump->mBlockedSequence++; } ++count; #endif nanosleep(&req, NULL); } #ifdef STATE_QUEUE_DUMP if (count > 1) { mMutatorDump->mBlockedSequence++; } #endif } } Loading
services/audioflinger/StateQueue.h +45 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,34 @@ namespace android { #ifdef STATE_QUEUE_DUMP // The StateQueueObserverDump and StateQueueMutatorDump keep // a cache of StateQueue statistics that can be logged by dumpsys. // Each individual native word-sized field is accessed atomically. But the // overall structure is non-atomic, that is there may be an inconsistency between fields. // No barriers or locks are used for either writing or reading. // Only POD types are permitted, and the contents shouldn't be trusted (i.e. do range checks). // It has a different lifetime than the StateQueue, and so it can't be a member of StateQueue. struct StateQueueObserverDump { StateQueueObserverDump() : mStateChanges(0) { } /*virtual*/ ~StateQueueObserverDump() { } unsigned mStateChanges; // incremented each time poll() detects a state change void dump(int fd); }; struct StateQueueMutatorDump { StateQueueMutatorDump() : mPushDirty(0), mPushAck(0), mBlockedSequence(0) { } /*virtual*/ ~StateQueueMutatorDump() { } unsigned mPushDirty; // incremented each time push() is called with a dirty state unsigned mPushAck; // incremented each time push(BLOCK_UNTIL_ACKED) is called unsigned mBlockedSequence; // incremented before and after each time that push() // blocks for more than one PUSH_BLOCK_ACK_NS; // if odd, then mutator is currently blocked inside push() void dump(int fd); }; #endif // manages a FIFO queue of states template<typename T> class StateQueue { Loading Loading @@ -69,6 +97,16 @@ public: // Return whether the current state is dirty (modified and not pushed). bool isDirty() const { return mIsDirty; } #ifdef STATE_QUEUE_DUMP // Register location of observer dump area void setObserverDump(StateQueueObserverDump *dump) { mObserverDump = dump != NULL ? dump : &mObserverDummyDump; } // Register location of mutator dump area void setMutatorDump(StateQueueMutatorDump *dump) { mMutatorDump = dump != NULL ? dump : &mMutatorDummyDump; } #endif private: static const unsigned kN = 4; // values != 4 are not supported by this code T mStates[kN]; // written by mutator, read by observer Loading @@ -87,6 +125,13 @@ private: bool mIsDirty; // whether mutating state has been modified since last push bool mIsInitialized; // whether mutating state has been initialized yet #ifdef STATE_QUEUE_DUMP StateQueueObserverDump mObserverDummyDump; // default area for observer dump if not set StateQueueObserverDump* mObserverDump; // pointer to active observer dump, always non-NULL StateQueueMutatorDump mMutatorDummyDump; // default area for mutator dump if not set StateQueueMutatorDump* mMutatorDump; // pointer to active mutator dump, always non-NULL #endif }; // class StateQueue } // namespace android Loading