1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // <IMPORTANT_WARNING>
18 // Design rules for threadLoop() are given in the comments at section "Fast mixer thread" of
19 // StateQueue.h.  In particular, avoid library and system calls except at well-known points.
20 // The design rules are only for threadLoop(), and don't apply to FastMixerDumpState methods.
21 // </IMPORTANT_WARNING>
22 
23 #define LOG_TAG "FastMixer"
24 //#define LOG_NDEBUG 0
25 
26 #define ATRACE_TAG ATRACE_TAG_AUDIO
27 
28 #include "Configuration.h"
29 #include <time.h>
30 #include <utils/Log.h>
31 #include <utils/Trace.h>
32 #include <system/audio.h>
33 #ifdef FAST_MIXER_STATISTICS
34 #include <cpustats/CentralTendencyStatistics.h>
35 #ifdef CPU_FREQUENCY_STATISTICS
36 #include <cpustats/ThreadCpuUsage.h>
37 #endif
38 #endif
39 #include <audio_utils/format.h>
40 #include "AudioMixer.h"
41 #include "FastMixer.h"
42 
43 #define FCC_2                       2   // fixed channel count assumption
44 
45 namespace android {
46 
47 /*static*/ const FastMixerState FastMixer::initial;
48 
FastMixer()49 FastMixer::FastMixer() : FastThread(),
50     slopNs(0),
51     // fastTrackNames
52     // generations
53     outputSink(NULL),
54     outputSinkGen(0),
55     mixer(NULL),
56     mSinkBuffer(NULL),
57     mSinkBufferSize(0),
58     mSinkChannelCount(FCC_2),
59     mMixerBuffer(NULL),
60     mMixerBufferSize(0),
61     mMixerBufferFormat(AUDIO_FORMAT_PCM_16_BIT),
62     mMixerBufferState(UNDEFINED),
63     format(Format_Invalid),
64     sampleRate(0),
65     fastTracksGen(0),
66     totalNativeFramesWritten(0),
67     // timestamp
68     nativeFramesWrittenButNotPresented(0)   // the = 0 is to silence the compiler
69 {
70     // FIXME pass initial as parameter to base class constructor, and make it static local
71     previous = &initial;
72     current = &initial;
73 
74     mDummyDumpState = &dummyDumpState;
75     // TODO: Add channel mask to NBAIO_Format.
76     // We assume that the channel mask must be a valid positional channel mask.
77     mSinkChannelMask = audio_channel_out_mask_from_count(mSinkChannelCount);
78 
79     unsigned i;
80     for (i = 0; i < FastMixerState::kMaxFastTracks; ++i) {
81         fastTrackNames[i] = -1;
82         generations[i] = 0;
83     }
84 #ifdef FAST_MIXER_STATISTICS
85     oldLoad.tv_sec = 0;
86     oldLoad.tv_nsec = 0;
87 #endif
88 }
89 
~FastMixer()90 FastMixer::~FastMixer()
91 {
92 }
93 
sq()94 FastMixerStateQueue* FastMixer::sq()
95 {
96     return &mSQ;
97 }
98 
poll()99 const FastThreadState *FastMixer::poll()
100 {
101     return mSQ.poll();
102 }
103 
setLog(NBLog::Writer * logWriter)104 void FastMixer::setLog(NBLog::Writer *logWriter)
105 {
106     if (mixer != NULL) {
107         mixer->setLog(logWriter);
108     }
109 }
110 
onIdle()111 void FastMixer::onIdle()
112 {
113     preIdle = *(const FastMixerState *)current;
114     current = &preIdle;
115 }
116 
onExit()117 void FastMixer::onExit()
118 {
119     delete mixer;
120     free(mMixerBuffer);
121     free(mSinkBuffer);
122 }
123 
isSubClassCommand(FastThreadState::Command command)124 bool FastMixer::isSubClassCommand(FastThreadState::Command command)
125 {
126     switch ((FastMixerState::Command) command) {
127     case FastMixerState::MIX:
128     case FastMixerState::WRITE:
129     case FastMixerState::MIX_WRITE:
130         return true;
131     default:
132         return false;
133     }
134 }
135 
onStateChange()136 void FastMixer::onStateChange()
137 {
138     const FastMixerState * const current = (const FastMixerState *) this->current;
139     const FastMixerState * const previous = (const FastMixerState *) this->previous;
140     FastMixerDumpState * const dumpState = (FastMixerDumpState *) this->dumpState;
141     const size_t frameCount = current->mFrameCount;
142 
143     // handle state change here, but since we want to diff the state,
144     // we're prepared for previous == &initial the first time through
145     unsigned previousTrackMask;
146 
147     // check for change in output HAL configuration
148     NBAIO_Format previousFormat = format;
149     if (current->mOutputSinkGen != outputSinkGen) {
150         outputSink = current->mOutputSink;
151         outputSinkGen = current->mOutputSinkGen;
152         if (outputSink == NULL) {
153             format = Format_Invalid;
154             sampleRate = 0;
155             mSinkChannelCount = 0;
156             mSinkChannelMask = AUDIO_CHANNEL_NONE;
157         } else {
158             format = outputSink->format();
159             sampleRate = Format_sampleRate(format);
160             mSinkChannelCount = Format_channelCount(format);
161             LOG_ALWAYS_FATAL_IF(mSinkChannelCount > AudioMixer::MAX_NUM_CHANNELS);
162 
163             // TODO: Add channel mask to NBAIO_Format
164             // We assume that the channel mask must be a valid positional channel mask.
165             mSinkChannelMask = audio_channel_out_mask_from_count(mSinkChannelCount);
166         }
167         dumpState->mSampleRate = sampleRate;
168     }
169 
170     if ((!Format_isEqual(format, previousFormat)) || (frameCount != previous->mFrameCount)) {
171         // FIXME to avoid priority inversion, don't delete here
172         delete mixer;
173         mixer = NULL;
174         free(mMixerBuffer);
175         mMixerBuffer = NULL;
176         free(mSinkBuffer);
177         mSinkBuffer = NULL;
178         if (frameCount > 0 && sampleRate > 0) {
179             // FIXME new may block for unbounded time at internal mutex of the heap
180             //       implementation; it would be better to have normal mixer allocate for us
181             //       to avoid blocking here and to prevent possible priority inversion
182             mixer = new AudioMixer(frameCount, sampleRate, FastMixerState::kMaxFastTracks);
183             const size_t mixerFrameSize = mSinkChannelCount
184                     * audio_bytes_per_sample(mMixerBufferFormat);
185             mMixerBufferSize = mixerFrameSize * frameCount;
186             (void)posix_memalign(&mMixerBuffer, 32, mMixerBufferSize);
187             const size_t sinkFrameSize = mSinkChannelCount
188                     * audio_bytes_per_sample(format.mFormat);
189             if (sinkFrameSize > mixerFrameSize) { // need a sink buffer
190                 mSinkBufferSize = sinkFrameSize * frameCount;
191                 (void)posix_memalign(&mSinkBuffer, 32, mSinkBufferSize);
192             }
193             periodNs = (frameCount * 1000000000LL) / sampleRate;    // 1.00
194             underrunNs = (frameCount * 1750000000LL) / sampleRate;  // 1.75
195             overrunNs = (frameCount * 500000000LL) / sampleRate;    // 0.50
196             forceNs = (frameCount * 950000000LL) / sampleRate;      // 0.95
197             warmupNs = (frameCount * 500000000LL) / sampleRate;     // 0.50
198         } else {
199             periodNs = 0;
200             underrunNs = 0;
201             overrunNs = 0;
202             forceNs = 0;
203             warmupNs = 0;
204         }
205         mMixerBufferState = UNDEFINED;
206 #if !LOG_NDEBUG
207         for (unsigned i = 0; i < FastMixerState::kMaxFastTracks; ++i) {
208             fastTrackNames[i] = -1;
209         }
210 #endif
211         // we need to reconfigure all active tracks
212         previousTrackMask = 0;
213         fastTracksGen = current->mFastTracksGen - 1;
214         dumpState->mFrameCount = frameCount;
215     } else {
216         previousTrackMask = previous->mTrackMask;
217     }
218 
219     // check for change in active track set
220     const unsigned currentTrackMask = current->mTrackMask;
221     dumpState->mTrackMask = currentTrackMask;
222     if (current->mFastTracksGen != fastTracksGen) {
223         ALOG_ASSERT(mMixerBuffer != NULL);
224         int name;
225 
226         // process removed tracks first to avoid running out of track names
227         unsigned removedTracks = previousTrackMask & ~currentTrackMask;
228         while (removedTracks != 0) {
229             int i = __builtin_ctz(removedTracks);
230             removedTracks &= ~(1 << i);
231             const FastTrack* fastTrack = &current->mFastTracks[i];
232             ALOG_ASSERT(fastTrack->mBufferProvider == NULL);
233             if (mixer != NULL) {
234                 name = fastTrackNames[i];
235                 ALOG_ASSERT(name >= 0);
236                 mixer->deleteTrackName(name);
237             }
238 #if !LOG_NDEBUG
239             fastTrackNames[i] = -1;
240 #endif
241             // don't reset track dump state, since other side is ignoring it
242             generations[i] = fastTrack->mGeneration;
243         }
244 
245         // now process added tracks
246         unsigned addedTracks = currentTrackMask & ~previousTrackMask;
247         while (addedTracks != 0) {
248             int i = __builtin_ctz(addedTracks);
249             addedTracks &= ~(1 << i);
250             const FastTrack* fastTrack = &current->mFastTracks[i];
251             AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider;
252             ALOG_ASSERT(bufferProvider != NULL && fastTrackNames[i] == -1);
253             if (mixer != NULL) {
254                 name = mixer->getTrackName(fastTrack->mChannelMask,
255                         fastTrack->mFormat, AUDIO_SESSION_OUTPUT_MIX);
256                 ALOG_ASSERT(name >= 0);
257                 fastTrackNames[i] = name;
258                 mixer->setBufferProvider(name, bufferProvider);
259                 mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
260                         (void *)mMixerBuffer);
261                 // newly allocated track names default to full scale volume
262                 mixer->setParameter(
263                         name,
264                         AudioMixer::TRACK,
265                         AudioMixer::MIXER_FORMAT, (void *)mMixerBufferFormat);
266                 mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT,
267                         (void *)(uintptr_t)fastTrack->mFormat);
268                 mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
269                         (void *)(uintptr_t)fastTrack->mChannelMask);
270                 mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK,
271                         (void *)(uintptr_t)mSinkChannelMask);
272                 mixer->enable(name);
273             }
274             generations[i] = fastTrack->mGeneration;
275         }
276 
277         // finally process (potentially) modified tracks; these use the same slot
278         // but may have a different buffer provider or volume provider
279         unsigned modifiedTracks = currentTrackMask & previousTrackMask;
280         while (modifiedTracks != 0) {
281             int i = __builtin_ctz(modifiedTracks);
282             modifiedTracks &= ~(1 << i);
283             const FastTrack* fastTrack = &current->mFastTracks[i];
284             if (fastTrack->mGeneration != generations[i]) {
285                 // this track was actually modified
286                 AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider;
287                 ALOG_ASSERT(bufferProvider != NULL);
288                 if (mixer != NULL) {
289                     name = fastTrackNames[i];
290                     ALOG_ASSERT(name >= 0);
291                     mixer->setBufferProvider(name, bufferProvider);
292                     if (fastTrack->mVolumeProvider == NULL) {
293                         float f = AudioMixer::UNITY_GAIN_FLOAT;
294                         mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &f);
295                         mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &f);
296                     }
297                     mixer->setParameter(name, AudioMixer::RESAMPLE,
298                             AudioMixer::REMOVE, NULL);
299                     mixer->setParameter(
300                             name,
301                             AudioMixer::TRACK,
302                             AudioMixer::MIXER_FORMAT, (void *)mMixerBufferFormat);
303                     mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT,
304                             (void *)(uintptr_t)fastTrack->mFormat);
305                     mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
306                             (void *)(uintptr_t)fastTrack->mChannelMask);
307                     mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK,
308                             (void *)(uintptr_t)mSinkChannelMask);
309                     // already enabled
310                 }
311                 generations[i] = fastTrack->mGeneration;
312             }
313         }
314 
315         fastTracksGen = current->mFastTracksGen;
316 
317         dumpState->mNumTracks = popcount(currentTrackMask);
318     }
319 }
320 
onWork()321 void FastMixer::onWork()
322 {
323     const FastMixerState * const current = (const FastMixerState *) this->current;
324     FastMixerDumpState * const dumpState = (FastMixerDumpState *) this->dumpState;
325     const FastMixerState::Command command = this->command;
326     const size_t frameCount = current->mFrameCount;
327 
328     if ((command & FastMixerState::MIX) && (mixer != NULL) && isWarm) {
329         ALOG_ASSERT(mMixerBuffer != NULL);
330         // for each track, update volume and check for underrun
331         unsigned currentTrackMask = current->mTrackMask;
332         while (currentTrackMask != 0) {
333             int i = __builtin_ctz(currentTrackMask);
334             currentTrackMask &= ~(1 << i);
335             const FastTrack* fastTrack = &current->mFastTracks[i];
336 
337             // Refresh the per-track timestamp
338             if (timestampStatus == NO_ERROR) {
339                 uint32_t trackFramesWrittenButNotPresented =
340                     nativeFramesWrittenButNotPresented;
341                 uint32_t trackFramesWritten = fastTrack->mBufferProvider->framesReleased();
342                 // Can't provide an AudioTimestamp before first frame presented,
343                 // or during the brief 32-bit wraparound window
344                 if (trackFramesWritten >= trackFramesWrittenButNotPresented) {
345                     AudioTimestamp perTrackTimestamp;
346                     perTrackTimestamp.mPosition =
347                             trackFramesWritten - trackFramesWrittenButNotPresented;
348                     perTrackTimestamp.mTime = timestamp.mTime;
349                     fastTrack->mBufferProvider->onTimestamp(perTrackTimestamp);
350                 }
351             }
352 
353             int name = fastTrackNames[i];
354             ALOG_ASSERT(name >= 0);
355             if (fastTrack->mVolumeProvider != NULL) {
356                 gain_minifloat_packed_t vlr = fastTrack->mVolumeProvider->getVolumeLR();
357                 float vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
358                 float vrf = float_from_gain(gain_minifloat_unpack_right(vlr));
359 
360                 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &vlf);
361                 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &vrf);
362             }
363             // FIXME The current implementation of framesReady() for fast tracks
364             // takes a tryLock, which can block
365             // up to 1 ms.  If enough active tracks all blocked in sequence, this would result
366             // in the overall fast mix cycle being delayed.  Should use a non-blocking FIFO.
367             size_t framesReady = fastTrack->mBufferProvider->framesReady();
368             if (ATRACE_ENABLED()) {
369                 // I wish we had formatted trace names
370                 char traceName[16];
371                 strcpy(traceName, "fRdy");
372                 traceName[4] = i + (i < 10 ? '0' : 'A' - 10);
373                 traceName[5] = '\0';
374                 ATRACE_INT(traceName, framesReady);
375             }
376             FastTrackDump *ftDump = &dumpState->mTracks[i];
377             FastTrackUnderruns underruns = ftDump->mUnderruns;
378             if (framesReady < frameCount) {
379                 if (framesReady == 0) {
380                     underruns.mBitFields.mEmpty++;
381                     underruns.mBitFields.mMostRecent = UNDERRUN_EMPTY;
382                     mixer->disable(name);
383                 } else {
384                     // allow mixing partial buffer
385                     underruns.mBitFields.mPartial++;
386                     underruns.mBitFields.mMostRecent = UNDERRUN_PARTIAL;
387                     mixer->enable(name);
388                 }
389             } else {
390                 underruns.mBitFields.mFull++;
391                 underruns.mBitFields.mMostRecent = UNDERRUN_FULL;
392                 mixer->enable(name);
393             }
394             ftDump->mUnderruns = underruns;
395             ftDump->mFramesReady = framesReady;
396         }
397 
398         int64_t pts;
399         if (outputSink == NULL || (OK != outputSink->getNextWriteTimestamp(&pts))) {
400             pts = AudioBufferProvider::kInvalidPTS;
401         }
402 
403         // process() is CPU-bound
404         mixer->process(pts);
405         mMixerBufferState = MIXED;
406     } else if (mMixerBufferState == MIXED) {
407         mMixerBufferState = UNDEFINED;
408     }
409     //bool didFullWrite = false;    // dumpsys could display a count of partial writes
410     if ((command & FastMixerState::WRITE) && (outputSink != NULL) && (mMixerBuffer != NULL)) {
411         if (mMixerBufferState == UNDEFINED) {
412             memset(mMixerBuffer, 0, mMixerBufferSize);
413             mMixerBufferState = ZEROED;
414         }
415         void *buffer = mSinkBuffer != NULL ? mSinkBuffer : mMixerBuffer;
416         if (format.mFormat != mMixerBufferFormat) { // sink format not the same as mixer format
417             memcpy_by_audio_format(buffer, format.mFormat, mMixerBuffer, mMixerBufferFormat,
418                     frameCount * Format_channelCount(format));
419         }
420         // if non-NULL, then duplicate write() to this non-blocking sink
421         NBAIO_Sink* teeSink;
422         if ((teeSink = current->mTeeSink) != NULL) {
423             (void) teeSink->write(buffer, frameCount);
424         }
425         // FIXME write() is non-blocking and lock-free for a properly implemented NBAIO sink,
426         //       but this code should be modified to handle both non-blocking and blocking sinks
427         dumpState->mWriteSequence++;
428         ATRACE_BEGIN("write");
429         ssize_t framesWritten = outputSink->write(buffer, frameCount);
430         ATRACE_END();
431         dumpState->mWriteSequence++;
432         if (framesWritten >= 0) {
433             ALOG_ASSERT((size_t) framesWritten <= frameCount);
434             totalNativeFramesWritten += framesWritten;
435             dumpState->mFramesWritten = totalNativeFramesWritten;
436             //if ((size_t) framesWritten == frameCount) {
437             //    didFullWrite = true;
438             //}
439         } else {
440             dumpState->mWriteErrors++;
441         }
442         attemptedWrite = true;
443         // FIXME count # of writes blocked excessively, CPU usage, etc. for dump
444 
445         timestampStatus = outputSink->getTimestamp(timestamp);
446         if (timestampStatus == NO_ERROR) {
447             uint32_t totalNativeFramesPresented = timestamp.mPosition;
448             if (totalNativeFramesPresented <= totalNativeFramesWritten) {
449                 nativeFramesWrittenButNotPresented =
450                     totalNativeFramesWritten - totalNativeFramesPresented;
451             } else {
452                 // HAL reported that more frames were presented than were written
453                 timestampStatus = INVALID_OPERATION;
454             }
455         }
456     }
457 }
458 
FastMixerDumpState(uint32_t samplingN)459 FastMixerDumpState::FastMixerDumpState(
460 #ifdef FAST_MIXER_STATISTICS
461         uint32_t samplingN
462 #endif
463         ) : FastThreadDumpState(),
464     mWriteSequence(0), mFramesWritten(0),
465     mNumTracks(0), mWriteErrors(0),
466     mSampleRate(0), mFrameCount(0),
467     mTrackMask(0)
468 {
469 #ifdef FAST_MIXER_STATISTICS
470     increaseSamplingN(samplingN);
471 #endif
472 }
473 
474 #ifdef FAST_MIXER_STATISTICS
increaseSamplingN(uint32_t samplingN)475 void FastMixerDumpState::increaseSamplingN(uint32_t samplingN)
476 {
477     if (samplingN <= mSamplingN || samplingN > kSamplingN || roundup(samplingN) != samplingN) {
478         return;
479     }
480     uint32_t additional = samplingN - mSamplingN;
481     // sample arrays aren't accessed atomically with respect to the bounds,
482     // so clearing reduces chance for dumpsys to read random uninitialized samples
483     memset(&mMonotonicNs[mSamplingN], 0, sizeof(mMonotonicNs[0]) * additional);
484     memset(&mLoadNs[mSamplingN], 0, sizeof(mLoadNs[0]) * additional);
485 #ifdef CPU_FREQUENCY_STATISTICS
486     memset(&mCpukHz[mSamplingN], 0, sizeof(mCpukHz[0]) * additional);
487 #endif
488     mSamplingN = samplingN;
489 }
490 #endif
491 
~FastMixerDumpState()492 FastMixerDumpState::~FastMixerDumpState()
493 {
494 }
495 
496 // helper function called by qsort()
compare_uint32_t(const void * pa,const void * pb)497 static int compare_uint32_t(const void *pa, const void *pb)
498 {
499     uint32_t a = *(const uint32_t *)pa;
500     uint32_t b = *(const uint32_t *)pb;
501     if (a < b) {
502         return -1;
503     } else if (a > b) {
504         return 1;
505     } else {
506         return 0;
507     }
508 }
509 
dump(int fd) const510 void FastMixerDumpState::dump(int fd) const
511 {
512     if (mCommand == FastMixerState::INITIAL) {
513         dprintf(fd, "  FastMixer not initialized\n");
514         return;
515     }
516 #define COMMAND_MAX 32
517     char string[COMMAND_MAX];
518     switch (mCommand) {
519     case FastMixerState::INITIAL:
520         strcpy(string, "INITIAL");
521         break;
522     case FastMixerState::HOT_IDLE:
523         strcpy(string, "HOT_IDLE");
524         break;
525     case FastMixerState::COLD_IDLE:
526         strcpy(string, "COLD_IDLE");
527         break;
528     case FastMixerState::EXIT:
529         strcpy(string, "EXIT");
530         break;
531     case FastMixerState::MIX:
532         strcpy(string, "MIX");
533         break;
534     case FastMixerState::WRITE:
535         strcpy(string, "WRITE");
536         break;
537     case FastMixerState::MIX_WRITE:
538         strcpy(string, "MIX_WRITE");
539         break;
540     default:
541         snprintf(string, COMMAND_MAX, "%d", mCommand);
542         break;
543     }
544     double measuredWarmupMs = (mMeasuredWarmupTs.tv_sec * 1000.0) +
545             (mMeasuredWarmupTs.tv_nsec / 1000000.0);
546     double mixPeriodSec = (double) mFrameCount / (double) mSampleRate;
547     dprintf(fd, "  FastMixer command=%s writeSequence=%u framesWritten=%u\n"
548                 "            numTracks=%u writeErrors=%u underruns=%u overruns=%u\n"
549                 "            sampleRate=%u frameCount=%zu measuredWarmup=%.3g ms, warmupCycles=%u\n"
550                 "            mixPeriod=%.2f ms\n",
551                  string, mWriteSequence, mFramesWritten,
552                  mNumTracks, mWriteErrors, mUnderruns, mOverruns,
553                  mSampleRate, mFrameCount, measuredWarmupMs, mWarmupCycles,
554                  mixPeriodSec * 1e3);
555 #ifdef FAST_MIXER_STATISTICS
556     // find the interval of valid samples
557     uint32_t bounds = mBounds;
558     uint32_t newestOpen = bounds & 0xFFFF;
559     uint32_t oldestClosed = bounds >> 16;
560     uint32_t n = (newestOpen - oldestClosed) & 0xFFFF;
561     if (n > mSamplingN) {
562         ALOGE("too many samples %u", n);
563         n = mSamplingN;
564     }
565     // statistics for monotonic (wall clock) time, thread raw CPU load in time, CPU clock frequency,
566     // and adjusted CPU load in MHz normalized for CPU clock frequency
567     CentralTendencyStatistics wall, loadNs;
568 #ifdef CPU_FREQUENCY_STATISTICS
569     CentralTendencyStatistics kHz, loadMHz;
570     uint32_t previousCpukHz = 0;
571 #endif
572     // Assuming a normal distribution for cycle times, three standard deviations on either side of
573     // the mean account for 99.73% of the population.  So if we take each tail to be 1/1000 of the
574     // sample set, we get 99.8% combined, or close to three standard deviations.
575     static const uint32_t kTailDenominator = 1000;
576     uint32_t *tail = n >= kTailDenominator ? new uint32_t[n] : NULL;
577     // loop over all the samples
578     for (uint32_t j = 0; j < n; ++j) {
579         size_t i = oldestClosed++ & (mSamplingN - 1);
580         uint32_t wallNs = mMonotonicNs[i];
581         if (tail != NULL) {
582             tail[j] = wallNs;
583         }
584         wall.sample(wallNs);
585         uint32_t sampleLoadNs = mLoadNs[i];
586         loadNs.sample(sampleLoadNs);
587 #ifdef CPU_FREQUENCY_STATISTICS
588         uint32_t sampleCpukHz = mCpukHz[i];
589         // skip bad kHz samples
590         if ((sampleCpukHz & ~0xF) != 0) {
591             kHz.sample(sampleCpukHz >> 4);
592             if (sampleCpukHz == previousCpukHz) {
593                 double megacycles = (double) sampleLoadNs * (double) (sampleCpukHz >> 4) * 1e-12;
594                 double adjMHz = megacycles / mixPeriodSec;  // _not_ wallNs * 1e9
595                 loadMHz.sample(adjMHz);
596             }
597         }
598         previousCpukHz = sampleCpukHz;
599 #endif
600     }
601     if (n) {
602         dprintf(fd, "  Simple moving statistics over last %.1f seconds:\n",
603                     wall.n() * mixPeriodSec);
604         dprintf(fd, "    wall clock time in ms per mix cycle:\n"
605                     "      mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
606                     wall.mean()*1e-6, wall.minimum()*1e-6, wall.maximum()*1e-6,
607                     wall.stddev()*1e-6);
608         dprintf(fd, "    raw CPU load in us per mix cycle:\n"
609                     "      mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
610                     loadNs.mean()*1e-3, loadNs.minimum()*1e-3, loadNs.maximum()*1e-3,
611                     loadNs.stddev()*1e-3);
612     } else {
613         dprintf(fd, "  No FastMixer statistics available currently\n");
614     }
615 #ifdef CPU_FREQUENCY_STATISTICS
616     dprintf(fd, "  CPU clock frequency in MHz:\n"
617                 "    mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
618                 kHz.mean()*1e-3, kHz.minimum()*1e-3, kHz.maximum()*1e-3, kHz.stddev()*1e-3);
619     dprintf(fd, "  adjusted CPU load in MHz (i.e. normalized for CPU clock frequency):\n"
620                 "    mean=%.1f min=%.1f max=%.1f stddev=%.1f\n",
621                 loadMHz.mean(), loadMHz.minimum(), loadMHz.maximum(), loadMHz.stddev());
622 #endif
623     if (tail != NULL) {
624         qsort(tail, n, sizeof(uint32_t), compare_uint32_t);
625         // assume same number of tail samples on each side, left and right
626         uint32_t count = n / kTailDenominator;
627         CentralTendencyStatistics left, right;
628         for (uint32_t i = 0; i < count; ++i) {
629             left.sample(tail[i]);
630             right.sample(tail[n - (i + 1)]);
631         }
632         dprintf(fd, "  Distribution of mix cycle times in ms for the tails (> ~3 stddev outliers):\n"
633                     "    left tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n"
634                     "    right tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
635                     left.mean()*1e-6, left.minimum()*1e-6, left.maximum()*1e-6, left.stddev()*1e-6,
636                     right.mean()*1e-6, right.minimum()*1e-6, right.maximum()*1e-6,
637                     right.stddev()*1e-6);
638         delete[] tail;
639     }
640 #endif
641     // The active track mask and track states are updated non-atomically.
642     // So if we relied on isActive to decide whether to display,
643     // then we might display an obsolete track or omit an active track.
644     // Instead we always display all tracks, with an indication
645     // of whether we think the track is active.
646     uint32_t trackMask = mTrackMask;
647     dprintf(fd, "  Fast tracks: kMaxFastTracks=%u activeMask=%#x\n",
648             FastMixerState::kMaxFastTracks, trackMask);
649     dprintf(fd, "  Index Active Full Partial Empty  Recent Ready\n");
650     for (uint32_t i = 0; i < FastMixerState::kMaxFastTracks; ++i, trackMask >>= 1) {
651         bool isActive = trackMask & 1;
652         const FastTrackDump *ftDump = &mTracks[i];
653         const FastTrackUnderruns& underruns = ftDump->mUnderruns;
654         const char *mostRecent;
655         switch (underruns.mBitFields.mMostRecent) {
656         case UNDERRUN_FULL:
657             mostRecent = "full";
658             break;
659         case UNDERRUN_PARTIAL:
660             mostRecent = "partial";
661             break;
662         case UNDERRUN_EMPTY:
663             mostRecent = "empty";
664             break;
665         default:
666             mostRecent = "?";
667             break;
668         }
669         dprintf(fd, "  %5u %6s %4u %7u %5u %7s %5zu\n", i, isActive ? "yes" : "no",
670                 (underruns.mBitFields.mFull) & UNDERRUN_MASK,
671                 (underruns.mBitFields.mPartial) & UNDERRUN_MASK,
672                 (underruns.mBitFields.mEmpty) & UNDERRUN_MASK,
673                 mostRecent, ftDump->mFramesReady);
674     }
675 }
676 
677 }   // namespace android
678