FastThread.cpp revision f9715e43ea73361321663514c44129c939c5db2f
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
36namespace android {
37
38FastThread::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
86FastThread::~FastThread()
87{
88}
89
90bool 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);
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