Home | History | Annotate | Download | only in audioflinger
      1 /*
      2  * Copyright (C) 2014 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 #define LOG_TAG "FastThread"
     18 //#define LOG_NDEBUG 0
     19 
     20 #define ATRACE_TAG ATRACE_TAG_AUDIO
     21 
     22 #include "Configuration.h"
     23 #include <linux/futex.h>
     24 #include <sys/syscall.h>
     25 #include <utils/Log.h>
     26 #include <utils/Trace.h>
     27 #include "FastThread.h"
     28 #include "FastThreadDumpState.h"
     29 
     30 #define FAST_DEFAULT_NS    999999999L   // ~1 sec: default time to sleep
     31 #define FAST_HOT_IDLE_NS     1000000L   // 1 ms: time to sleep while hot idling
     32 #define MIN_WARMUP_CYCLES          2    // minimum number of consecutive in-range loop cycles
     33                                         // to wait for warmup
     34 #define MAX_WARMUP_CYCLES         10    // maximum number of loop cycles to wait for warmup
     35 
     36 namespace android {
     37 
     38 FastThread::FastThread(const char *cycleMs, const char *loadUs) : Thread(false /*canCallJava*/),
     39     // re-initialized to &sInitial by subclass constructor
     40     mPrevious(NULL), mCurrent(NULL),
     41     /* mOldTs({0, 0}), */
     42     mOldTsValid(false),
     43     mSleepNs(-1),
     44     mPeriodNs(0),
     45     mUnderrunNs(0),
     46     mOverrunNs(0),
     47     mForceNs(0),
     48     mWarmupNsMin(0),
     49     mWarmupNsMax(LONG_MAX),
     50     // re-initialized to &mDummySubclassDumpState by subclass constructor
     51     mDummyDumpState(NULL),
     52     mDumpState(NULL),
     53     mIgnoreNextOverrun(true),
     54 #ifdef FAST_THREAD_STATISTICS
     55     // mOldLoad
     56     mOldLoadValid(false),
     57     mBounds(0),
     58     mFull(false),
     59     // mTcu
     60 #endif
     61     mColdGen(0),
     62     mIsWarm(false),
     63     /* mMeasuredWarmupTs({0, 0}), */
     64     mWarmupCycles(0),
     65     mWarmupConsecutiveInRangeCycles(0),
     66     // mDummyLogWriter
     67     mLogWriter(&mDummyLogWriter),
     68     mTimestampStatus(INVALID_OPERATION),
     69 
     70     mCommand(FastThreadState::INITIAL),
     71 #if 0
     72     frameCount(0),
     73 #endif
     74     mAttemptedWrite(false)
     75     // mCycleMs(cycleMs)
     76     // mLoadUs(loadUs)
     77 {
     78     mOldTs.tv_sec = 0;
     79     mOldTs.tv_nsec = 0;
     80     mMeasuredWarmupTs.tv_sec = 0;
     81     mMeasuredWarmupTs.tv_nsec = 0;
     82     strlcpy(mCycleMs, cycleMs, sizeof(mCycleMs));
     83     strlcpy(mLoadUs, loadUs, sizeof(mLoadUs));
     84 }
     85 
     86 FastThread::~FastThread()
     87 {
     88 }
     89 
     90 bool FastThread::threadLoop()
     91 {
     92     for (;;) {
     93 
     94         // either nanosleep, sched_yield, or busy wait
     95         if (mSleepNs >= 0) {
     96             if (mSleepNs > 0) {
     97                 ALOG_ASSERT(mSleepNs < 1000000000);
     98                 const struct timespec req = {0, mSleepNs};
     99                 nanosleep(&req, NULL);
    100             } else {
    101                 sched_yield();
    102             }
    103         }
    104         // default to long sleep for next cycle
    105         mSleepNs = FAST_DEFAULT_NS;
    106 
    107         // poll for state change
    108         const FastThreadState *next = poll();
    109         if (next == NULL) {
    110             // continue to use the default initial state until a real state is available
    111             // FIXME &sInitial not available, should save address earlier
    112             //ALOG_ASSERT(mCurrent == &sInitial && previous == &sInitial);
    113             next = mCurrent;
    114         }
    115 
    116         mCommand = next->mCommand;
    117         if (next != mCurrent) {
    118 
    119             // As soon as possible of learning of a new dump area, start using it
    120             mDumpState = next->mDumpState != NULL ? next->mDumpState : mDummyDumpState;
    121             mLogWriter = next->mNBLogWriter != NULL ? next->mNBLogWriter : &mDummyLogWriter;
    122             setLog(mLogWriter);
    123 
    124             // We want to always have a valid reference to the previous (non-idle) state.
    125             // However, the state queue only guarantees access to current and previous states.
    126             // So when there is a transition from a non-idle state into an idle state, we make a
    127             // copy of the last known non-idle state so it is still available on return from idle.
    128             // The possible transitions are:
    129             //  non-idle -> non-idle    update previous from current in-place
    130             //  non-idle -> idle        update previous from copy of current
    131             //  idle     -> idle        don't update previous
    132             //  idle     -> non-idle    don't update previous
    133             if (!(mCurrent->mCommand & FastThreadState::IDLE)) {
    134                 if (mCommand & FastThreadState::IDLE) {
    135                     onIdle();
    136                     mOldTsValid = false;
    137 #ifdef FAST_THREAD_STATISTICS
    138                     mOldLoadValid = false;
    139 #endif
    140                     mIgnoreNextOverrun = true;
    141                 }
    142                 mPrevious = mCurrent;
    143             }
    144             mCurrent = next;
    145         }
    146 #if !LOG_NDEBUG
    147         next = NULL;    // not referenced again
    148 #endif
    149 
    150         mDumpState->mCommand = mCommand;
    151 
    152         // FIXME what does this comment mean?
    153         // << current, previous, command, dumpState >>
    154 
    155         switch (mCommand) {
    156         case FastThreadState::INITIAL:
    157         case FastThreadState::HOT_IDLE:
    158             mSleepNs = FAST_HOT_IDLE_NS;
    159             continue;
    160         case FastThreadState::COLD_IDLE:
    161             // only perform a cold idle command once
    162             // FIXME consider checking previous state and only perform if previous != COLD_IDLE
    163             if (mCurrent->mColdGen != mColdGen) {
    164                 int32_t *coldFutexAddr = mCurrent->mColdFutexAddr;
    165                 ALOG_ASSERT(coldFutexAddr != NULL);
    166                 int32_t old = android_atomic_dec(coldFutexAddr);
    167                 if (old <= 0) {
    168                     syscall(__NR_futex, coldFutexAddr, FUTEX_WAIT_PRIVATE, old - 1, NULL);
    169                 }
    170                 int policy = sched_getscheduler(0) & ~SCHED_RESET_ON_FORK;
    171                 if (!(policy == SCHED_FIFO || policy == SCHED_RR)) {
    172                     ALOGE("did not receive expected priority boost");
    173                 }
    174                 // This may be overly conservative; there could be times that the normal mixer
    175                 // requests such a brief cold idle that it doesn't require resetting this flag.
    176                 mIsWarm = false;
    177                 mMeasuredWarmupTs.tv_sec = 0;
    178                 mMeasuredWarmupTs.tv_nsec = 0;
    179                 mWarmupCycles = 0;
    180                 mWarmupConsecutiveInRangeCycles = 0;
    181                 mSleepNs = -1;
    182                 mColdGen = mCurrent->mColdGen;
    183 #ifdef FAST_THREAD_STATISTICS
    184                 mBounds = 0;
    185                 mFull = false;
    186 #endif
    187                 mOldTsValid = !clock_gettime(CLOCK_MONOTONIC, &mOldTs);
    188                 mTimestampStatus = INVALID_OPERATION;
    189             } else {
    190                 mSleepNs = FAST_HOT_IDLE_NS;
    191             }
    192             continue;
    193         case FastThreadState::EXIT:
    194             onExit();
    195             return false;
    196         default:
    197             LOG_ALWAYS_FATAL_IF(!isSubClassCommand(mCommand));
    198             break;
    199         }
    200 
    201         // there is a non-idle state available to us; did the state change?
    202         if (mCurrent != mPrevious) {
    203             onStateChange();
    204 #if 1   // FIXME shouldn't need this
    205             // only process state change once
    206             mPrevious = mCurrent;
    207 #endif
    208         }
    209 
    210         // do work using current state here
    211         mAttemptedWrite = false;
    212         onWork();
    213 
    214         // To be exactly periodic, compute the next sleep time based on current time.
    215         // This code doesn't have long-term stability when the sink is non-blocking.
    216         // FIXME To avoid drift, use the local audio clock or watch the sink's fill status.
    217         struct timespec newTs;
    218         int rc = clock_gettime(CLOCK_MONOTONIC, &newTs);
    219         if (rc == 0) {
    220             //mLogWriter->logTimestamp(newTs);
    221             if (mOldTsValid) {
    222                 time_t sec = newTs.tv_sec - mOldTs.tv_sec;
    223                 long nsec = newTs.tv_nsec - mOldTs.tv_nsec;
    224                 ALOGE_IF(sec < 0 || (sec == 0 && nsec < 0),
    225                         "clock_gettime(CLOCK_MONOTONIC) failed: was %ld.%09ld but now %ld.%09ld",
    226                         mOldTs.tv_sec, mOldTs.tv_nsec, newTs.tv_sec, newTs.tv_nsec);
    227                 if (nsec < 0) {
    228                     --sec;
    229                     nsec += 1000000000;
    230                 }
    231                 // To avoid an initial underrun on fast tracks after exiting standby,
    232                 // do not start pulling data from tracks and mixing until warmup is complete.
    233                 // Warmup is considered complete after the earlier of:
    234                 //      MIN_WARMUP_CYCLES consecutive in-range write() attempts,
    235                 //          where "in-range" means mWarmupNsMin <= cycle time <= mWarmupNsMax
    236                 //      MAX_WARMUP_CYCLES write() attempts.
    237                 // This is overly conservative, but to get better accuracy requires a new HAL API.
    238                 if (!mIsWarm && mAttemptedWrite) {
    239                     mMeasuredWarmupTs.tv_sec += sec;
    240                     mMeasuredWarmupTs.tv_nsec += nsec;
    241                     if (mMeasuredWarmupTs.tv_nsec >= 1000000000) {
    242                         mMeasuredWarmupTs.tv_sec++;
    243                         mMeasuredWarmupTs.tv_nsec -= 1000000000;
    244                     }
    245                     ++mWarmupCycles;
    246                     if (mWarmupNsMin <= nsec && nsec <= mWarmupNsMax) {
    247                         ALOGV("warmup cycle %d in range: %.03f ms", mWarmupCycles, nsec * 1e-9);
    248                         ++mWarmupConsecutiveInRangeCycles;
    249                     } else {
    250                         ALOGV("warmup cycle %d out of range: %.03f ms", mWarmupCycles, nsec * 1e-9);
    251                         mWarmupConsecutiveInRangeCycles = 0;
    252                     }
    253                     if ((mWarmupConsecutiveInRangeCycles >= MIN_WARMUP_CYCLES) ||
    254                             (mWarmupCycles >= MAX_WARMUP_CYCLES)) {
    255                         mIsWarm = true;
    256                         mDumpState->mMeasuredWarmupTs = mMeasuredWarmupTs;
    257                         mDumpState->mWarmupCycles = mWarmupCycles;
    258                     }
    259                 }
    260                 mSleepNs = -1;
    261                 if (mIsWarm) {
    262                     if (sec > 0 || nsec > mUnderrunNs) {
    263                         ATRACE_NAME("underrun");
    264                         // FIXME only log occasionally
    265                         ALOGV("underrun: time since last cycle %d.%03ld sec",
    266                                 (int) sec, nsec / 1000000L);
    267                         mDumpState->mUnderruns++;
    268                         mIgnoreNextOverrun = true;
    269                     } else if (nsec < mOverrunNs) {
    270                         if (mIgnoreNextOverrun) {
    271                             mIgnoreNextOverrun = false;
    272                         } else {
    273                             // FIXME only log occasionally
    274                             ALOGV("overrun: time since last cycle %d.%03ld sec",
    275                                     (int) sec, nsec / 1000000L);
    276                             mDumpState->mOverruns++;
    277                         }
    278                         // This forces a minimum cycle time. It:
    279                         //  - compensates for an audio HAL with jitter due to sample rate conversion
    280                         //  - works with a variable buffer depth audio HAL that never pulls at a
    281                         //    rate < than mOverrunNs per buffer.
    282                         //  - recovers from overrun immediately after underrun
    283                         // It doesn't work with a non-blocking audio HAL.
    284                         mSleepNs = mForceNs - nsec;
    285                     } else {
    286                         mIgnoreNextOverrun = false;
    287                     }
    288                 }
    289 #ifdef FAST_THREAD_STATISTICS
    290                 if (mIsWarm) {
    291                     // advance the FIFO queue bounds
    292                     size_t i = mBounds & (mDumpState->mSamplingN - 1);
    293                     mBounds = (mBounds & 0xFFFF0000) | ((mBounds + 1) & 0xFFFF);
    294                     if (mFull) {
    295                         mBounds += 0x10000;
    296                     } else if (!(mBounds & (mDumpState->mSamplingN - 1))) {
    297                         mFull = true;
    298                     }
    299                     // compute the delta value of clock_gettime(CLOCK_MONOTONIC)
    300                     uint32_t monotonicNs = nsec;
    301                     if (sec > 0 && sec < 4) {
    302                         monotonicNs += sec * 1000000000;
    303                     }
    304                     // compute raw CPU load = delta value of clock_gettime(CLOCK_THREAD_CPUTIME_ID)
    305                     uint32_t loadNs = 0;
    306                     struct timespec newLoad;
    307                     rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &newLoad);
    308                     if (rc == 0) {
    309                         if (mOldLoadValid) {
    310                             sec = newLoad.tv_sec - mOldLoad.tv_sec;
    311                             nsec = newLoad.tv_nsec - mOldLoad.tv_nsec;
    312                             if (nsec < 0) {
    313                                 --sec;
    314                                 nsec += 1000000000;
    315                             }
    316                             loadNs = nsec;
    317                             if (sec > 0 && sec < 4) {
    318                                 loadNs += sec * 1000000000;
    319                             }
    320                         } else {
    321                             // first time through the loop
    322                             mOldLoadValid = true;
    323                         }
    324                         mOldLoad = newLoad;
    325                     }
    326 #ifdef CPU_FREQUENCY_STATISTICS
    327                     // get the absolute value of CPU clock frequency in kHz
    328                     int cpuNum = sched_getcpu();
    329                     uint32_t kHz = mTcu.getCpukHz(cpuNum);
    330                     kHz = (kHz << 4) | (cpuNum & 0xF);
    331 #endif
    332                     // save values in FIFO queues for dumpsys
    333                     // these stores #1, #2, #3 are not atomic with respect to each other,
    334                     // or with respect to store #4 below
    335                     mDumpState->mMonotonicNs[i] = monotonicNs;
    336                     mDumpState->mLoadNs[i] = loadNs;
    337 #ifdef CPU_FREQUENCY_STATISTICS
    338                     mDumpState->mCpukHz[i] = kHz;
    339 #endif
    340                     // this store #4 is not atomic with respect to stores #1, #2, #3 above, but
    341                     // the newest open & oldest closed halves are atomic with respect to each other
    342                     mDumpState->mBounds = mBounds;
    343                     ATRACE_INT(mCycleMs, monotonicNs / 1000000);
    344                     ATRACE_INT(mLoadUs, loadNs / 1000);
    345                 }
    346 #endif
    347             } else {
    348                 // first time through the loop
    349                 mOldTsValid = true;
    350                 mSleepNs = mPeriodNs;
    351                 mIgnoreNextOverrun = true;
    352             }
    353             mOldTs = newTs;
    354         } else {
    355             // monotonic clock is broken
    356             mOldTsValid = false;
    357             mSleepNs = mPeriodNs;
    358         }
    359 
    360     }   // for (;;)
    361 
    362     // never return 'true'; Thread::_threadLoop() locks mutex which can result in priority inversion
    363 }
    364 
    365 }   // namespace android
    366