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