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