FastMixer.cpp revision 9a59276fb465e492138e0576523b54079671e8f4
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
45namespace android {
46
47/*static*/ const FastMixerState FastMixer::initial;
48
49FastMixer::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
90FastMixer::~FastMixer()
91{
92}
93
94FastMixerStateQueue* FastMixer::sq()
95{
96    return &mSQ;
97}
98
99const FastThreadState *FastMixer::poll()
100{
101    return mSQ.poll();
102}
103
104void FastMixer::setLog(NBLog::Writer *logWriter)
105{
106    if (mixer != NULL) {
107        mixer->setLog(logWriter);
108    }
109}
110
111void FastMixer::onIdle()
112{
113    preIdle = *(const FastMixerState *)current;
114    current = &preIdle;
115}
116
117void FastMixer::onExit()
118{
119    delete mixer;
120    free(mMixerBuffer);
121    free(mSinkBuffer);
122}
123
124bool 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
136void 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
321void 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(mMixerBuffer, 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
459FastMixerDumpState::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
475void 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
492FastMixerDumpState::~FastMixerDumpState()
493{
494}
495
496// helper function called by qsort()
497static 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
510void 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