blob: 2ebdbc15952c53073c55fb7de369e28b9e3328e6 [file] [log] [blame]
Glenn Kasten22340022014-04-07 12:04:41 -07001/*
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"
Elliott Hughese348c5b2014-05-21 18:47:50 -070023#include <linux/futex.h>
24#include <sys/syscall.h>
Eric Tanfefe3162018-09-07 10:09:11 -070025#include <audio_utils/clock.h>
Mathias Agopian05d19b02017-02-28 16:28:19 -080026#include <cutils/atomic.h>
Glenn Kasten22340022014-04-07 12:04:41 -070027#include <utils/Log.h>
Glenn Kasten22340022014-04-07 12:04:41 -070028#include <utils/Trace.h>
29#include "FastThread.h"
Glenn Kasten045ee7e2015-02-17 16:22:04 -080030#include "FastThreadDumpState.h"
Andy Hungb776e372023-05-24 11:53:47 -070031#include <afutils/TypedLogger.h>
Glenn Kasten22340022014-04-07 12:04:41 -070032
33#define FAST_DEFAULT_NS 999999999L // ~1 sec: default time to sleep
34#define FAST_HOT_IDLE_NS 1000000L // 1 ms: time to sleep while hot idling
Glenn Kastend2123e62015-01-29 10:02:44 -080035#define MIN_WARMUP_CYCLES 2 // minimum number of consecutive in-range loop cycles
36 // to wait for warmup
Glenn Kasten22340022014-04-07 12:04:41 -070037#define MAX_WARMUP_CYCLES 10 // maximum number of loop cycles to wait for warmup
38
39namespace android {
40
Glenn Kastenf9715e42016-07-13 14:02:03 -070041FastThread::FastThread(const char *cycleMs, const char *loadUs) : Thread(false /*canCallJava*/),
Glenn Kastene4a7ce22015-03-03 11:23:17 -080042 // re-initialized to &sInitial by subclass constructor
Andy Hungf0859f32023-05-25 16:28:04 -070043 mPrevious(nullptr), mCurrent(nullptr),
Glenn Kastene4a7ce22015-03-03 11:23:17 -080044 /* mOldTs({0, 0}), */
45 mOldTsValid(false),
46 mSleepNs(-1),
47 mPeriodNs(0),
48 mUnderrunNs(0),
49 mOverrunNs(0),
50 mForceNs(0),
51 mWarmupNsMin(0),
52 mWarmupNsMax(LONG_MAX),
53 // re-initialized to &mDummySubclassDumpState by subclass constructor
Andy Hungf0859f32023-05-25 16:28:04 -070054 mDummyDumpState(nullptr),
55 mDumpState(nullptr),
Glenn Kastene4a7ce22015-03-03 11:23:17 -080056 mIgnoreNextOverrun(true),
Glenn Kasten214b4062015-03-02 14:15:47 -080057#ifdef FAST_THREAD_STATISTICS
Glenn Kastene4a7ce22015-03-03 11:23:17 -080058 // mOldLoad
59 mOldLoadValid(false),
60 mBounds(0),
61 mFull(false),
62 // mTcu
Glenn Kasten22340022014-04-07 12:04:41 -070063#endif
Glenn Kastene4a7ce22015-03-03 11:23:17 -080064 mColdGen(0),
65 mIsWarm(false),
66 /* mMeasuredWarmupTs({0, 0}), */
67 mWarmupCycles(0),
68 mWarmupConsecutiveInRangeCycles(0),
Glenn Kastene4a7ce22015-03-03 11:23:17 -080069 mTimestampStatus(INVALID_OPERATION),
Glenn Kasten22340022014-04-07 12:04:41 -070070
Glenn Kastene4a7ce22015-03-03 11:23:17 -080071 mCommand(FastThreadState::INITIAL),
Glenn Kasten22340022014-04-07 12:04:41 -070072#if 0
73 frameCount(0),
74#endif
Glenn Kastene4a7ce22015-03-03 11:23:17 -080075 mAttemptedWrite(false)
Glenn Kastenf9715e42016-07-13 14:02:03 -070076 // mCycleMs(cycleMs)
77 // mLoadUs(loadUs)
Glenn Kasten22340022014-04-07 12:04:41 -070078{
Glenn Kastene4a7ce22015-03-03 11:23:17 -080079 mOldTs.tv_sec = 0;
80 mOldTs.tv_nsec = 0;
81 mMeasuredWarmupTs.tv_sec = 0;
82 mMeasuredWarmupTs.tv_nsec = 0;
Glenn Kastenf9715e42016-07-13 14:02:03 -070083 strlcpy(mCycleMs, cycleMs, sizeof(mCycleMs));
84 strlcpy(mLoadUs, loadUs, sizeof(mLoadUs));
Glenn Kasten22340022014-04-07 12:04:41 -070085}
86
Glenn Kasten22340022014-04-07 12:04:41 -070087bool FastThread::threadLoop()
88{
Glenn Kasten388d5712017-04-07 14:38:41 -070089 // LOGT now works even if tlNBLogWriter is nullptr, but we're considering changing that,
Glenn Kasteneef598c2017-04-03 14:41:13 -070090 // so this initialization permits a future change to remove the check for nullptr.
Andy Hung4bf583b2023-05-30 18:10:23 -070091 aflog::setThreadWriter(mDummyNBLogWriter.get());
Glenn Kasten22340022014-04-07 12:04:41 -070092 for (;;) {
93
94 // either nanosleep, sched_yield, or busy wait
Glenn Kastene4a7ce22015-03-03 11:23:17 -080095 if (mSleepNs >= 0) {
96 if (mSleepNs > 0) {
97 ALOG_ASSERT(mSleepNs < 1000000000);
98 const struct timespec req = {0, mSleepNs};
Andy Hungf0859f32023-05-25 16:28:04 -070099 nanosleep(&req, nullptr);
Glenn Kasten22340022014-04-07 12:04:41 -0700100 } else {
101 sched_yield();
102 }
103 }
104 // default to long sleep for next cycle
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800105 mSleepNs = FAST_DEFAULT_NS;
Glenn Kasten22340022014-04-07 12:04:41 -0700106
107 // poll for state change
108 const FastThreadState *next = poll();
Andy Hungf0859f32023-05-25 16:28:04 -0700109 if (next == nullptr) {
Glenn Kasten22340022014-04-07 12:04:41 -0700110 // continue to use the default initial state until a real state is available
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800111 // FIXME &sInitial not available, should save address earlier
112 //ALOG_ASSERT(mCurrent == &sInitial && previous == &sInitial);
113 next = mCurrent;
Glenn Kasten22340022014-04-07 12:04:41 -0700114 }
115
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800116 mCommand = next->mCommand;
117 if (next != mCurrent) {
Glenn Kasten22340022014-04-07 12:04:41 -0700118
119 // As soon as possible of learning of a new dump area, start using it
Andy Hungf0859f32023-05-25 16:28:04 -0700120 mDumpState = next->mDumpState != nullptr ? next->mDumpState : mDummyDumpState;
Andy Hung4bf583b2023-05-30 18:10:23 -0700121 NBLog::Writer * const writer = next->mNBLogWriter != nullptr ?
Mikhail Naganov01d09d92018-09-18 12:38:57 -0700122 next->mNBLogWriter : mDummyNBLogWriter.get();
Andy Hung4bf583b2023-05-30 18:10:23 -0700123 aflog::setThreadWriter(writer);
124 setNBLogWriter(writer); // This is used for debugging only
Glenn Kasten22340022014-04-07 12:04:41 -0700125
126 // We want to always have a valid reference to the previous (non-idle) state.
127 // However, the state queue only guarantees access to current and previous states.
128 // So when there is a transition from a non-idle state into an idle state, we make a
129 // copy of the last known non-idle state so it is still available on return from idle.
130 // The possible transitions are:
131 // non-idle -> non-idle update previous from current in-place
132 // non-idle -> idle update previous from copy of current
133 // idle -> idle don't update previous
134 // idle -> non-idle don't update previous
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800135 if (!(mCurrent->mCommand & FastThreadState::IDLE)) {
136 if (mCommand & FastThreadState::IDLE) {
Glenn Kasten22340022014-04-07 12:04:41 -0700137 onIdle();
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800138 mOldTsValid = false;
Glenn Kasten214b4062015-03-02 14:15:47 -0800139#ifdef FAST_THREAD_STATISTICS
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800140 mOldLoadValid = false;
Glenn Kasten22340022014-04-07 12:04:41 -0700141#endif
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800142 mIgnoreNextOverrun = true;
Glenn Kasten22340022014-04-07 12:04:41 -0700143 }
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800144 mPrevious = mCurrent;
Glenn Kasten22340022014-04-07 12:04:41 -0700145 }
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800146 mCurrent = next;
Glenn Kasten22340022014-04-07 12:04:41 -0700147 }
148#if !LOG_NDEBUG
Andy Hungf0859f32023-05-25 16:28:04 -0700149 next = nullptr; // not referenced again
Glenn Kasten22340022014-04-07 12:04:41 -0700150#endif
151
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800152 mDumpState->mCommand = mCommand;
Glenn Kasten22340022014-04-07 12:04:41 -0700153
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800154 // FIXME what does this comment mean?
Glenn Kasten22340022014-04-07 12:04:41 -0700155 // << current, previous, command, dumpState >>
156
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800157 switch (mCommand) {
Glenn Kasten22340022014-04-07 12:04:41 -0700158 case FastThreadState::INITIAL:
159 case FastThreadState::HOT_IDLE:
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800160 mSleepNs = FAST_HOT_IDLE_NS;
Glenn Kasten22340022014-04-07 12:04:41 -0700161 continue;
162 case FastThreadState::COLD_IDLE:
163 // only perform a cold idle command once
164 // FIXME consider checking previous state and only perform if previous != COLD_IDLE
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800165 if (mCurrent->mColdGen != mColdGen) {
166 int32_t *coldFutexAddr = mCurrent->mColdFutexAddr;
Andy Hungf0859f32023-05-25 16:28:04 -0700167 ALOG_ASSERT(coldFutexAddr != nullptr);
168 const int32_t old = android_atomic_dec(coldFutexAddr);
Glenn Kasten22340022014-04-07 12:04:41 -0700169 if (old <= 0) {
Andy Hungf0859f32023-05-25 16:28:04 -0700170 syscall(__NR_futex, coldFutexAddr, FUTEX_WAIT_PRIVATE, old - 1, nullptr);
Glenn Kasten22340022014-04-07 12:04:41 -0700171 }
Andy Hungf0859f32023-05-25 16:28:04 -0700172 const int policy = sched_getscheduler(0) & ~SCHED_RESET_ON_FORK;
Glenn Kasten22340022014-04-07 12:04:41 -0700173 if (!(policy == SCHED_FIFO || policy == SCHED_RR)) {
Glenn Kasten1bfe09a2017-02-21 13:05:56 -0800174 ALOGE("did not receive expected priority boost on time");
Glenn Kasten22340022014-04-07 12:04:41 -0700175 }
176 // This may be overly conservative; there could be times that the normal mixer
177 // requests such a brief cold idle that it doesn't require resetting this flag.
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800178 mIsWarm = false;
179 mMeasuredWarmupTs.tv_sec = 0;
180 mMeasuredWarmupTs.tv_nsec = 0;
181 mWarmupCycles = 0;
182 mWarmupConsecutiveInRangeCycles = 0;
183 mSleepNs = -1;
184 mColdGen = mCurrent->mColdGen;
Glenn Kasten214b4062015-03-02 14:15:47 -0800185#ifdef FAST_THREAD_STATISTICS
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800186 mBounds = 0;
187 mFull = false;
Glenn Kasten22340022014-04-07 12:04:41 -0700188#endif
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800189 mOldTsValid = !clock_gettime(CLOCK_MONOTONIC, &mOldTs);
190 mTimestampStatus = INVALID_OPERATION;
Glenn Kasten22340022014-04-07 12:04:41 -0700191 } else {
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800192 mSleepNs = FAST_HOT_IDLE_NS;
Glenn Kasten22340022014-04-07 12:04:41 -0700193 }
194 continue;
195 case FastThreadState::EXIT:
196 onExit();
197 return false;
198 default:
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800199 LOG_ALWAYS_FATAL_IF(!isSubClassCommand(mCommand));
Glenn Kasten22340022014-04-07 12:04:41 -0700200 break;
201 }
202
203 // there is a non-idle state available to us; did the state change?
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800204 if (mCurrent != mPrevious) {
Glenn Kasten22340022014-04-07 12:04:41 -0700205 onStateChange();
206#if 1 // FIXME shouldn't need this
207 // only process state change once
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800208 mPrevious = mCurrent;
Glenn Kasten22340022014-04-07 12:04:41 -0700209#endif
210 }
211
212 // do work using current state here
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800213 mAttemptedWrite = false;
Glenn Kasten22340022014-04-07 12:04:41 -0700214 onWork();
215
216 // To be exactly periodic, compute the next sleep time based on current time.
217 // This code doesn't have long-term stability when the sink is non-blocking.
218 // FIXME To avoid drift, use the local audio clock or watch the sink's fill status.
219 struct timespec newTs;
220 int rc = clock_gettime(CLOCK_MONOTONIC, &newTs);
221 if (rc == 0) {
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800222 if (mOldTsValid) {
223 time_t sec = newTs.tv_sec - mOldTs.tv_sec;
224 long nsec = newTs.tv_nsec - mOldTs.tv_nsec;
Glenn Kasten22340022014-04-07 12:04:41 -0700225 ALOGE_IF(sec < 0 || (sec == 0 && nsec < 0),
226 "clock_gettime(CLOCK_MONOTONIC) failed: was %ld.%09ld but now %ld.%09ld",
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800227 mOldTs.tv_sec, mOldTs.tv_nsec, newTs.tv_sec, newTs.tv_nsec);
Glenn Kasten22340022014-04-07 12:04:41 -0700228 if (nsec < 0) {
229 --sec;
230 nsec += 1000000000;
231 }
232 // To avoid an initial underrun on fast tracks after exiting standby,
233 // do not start pulling data from tracks and mixing until warmup is complete.
234 // Warmup is considered complete after the earlier of:
Glenn Kastend2123e62015-01-29 10:02:44 -0800235 // MIN_WARMUP_CYCLES consecutive in-range write() attempts,
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800236 // where "in-range" means mWarmupNsMin <= cycle time <= mWarmupNsMax
Glenn Kasten22340022014-04-07 12:04:41 -0700237 // MAX_WARMUP_CYCLES write() attempts.
238 // This is overly conservative, but to get better accuracy requires a new HAL API.
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800239 if (!mIsWarm && mAttemptedWrite) {
240 mMeasuredWarmupTs.tv_sec += sec;
241 mMeasuredWarmupTs.tv_nsec += nsec;
242 if (mMeasuredWarmupTs.tv_nsec >= 1000000000) {
243 mMeasuredWarmupTs.tv_sec++;
244 mMeasuredWarmupTs.tv_nsec -= 1000000000;
Glenn Kasten22340022014-04-07 12:04:41 -0700245 }
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800246 ++mWarmupCycles;
247 if (mWarmupNsMin <= nsec && nsec <= mWarmupNsMax) {
248 ALOGV("warmup cycle %d in range: %.03f ms", mWarmupCycles, nsec * 1e-9);
249 ++mWarmupConsecutiveInRangeCycles;
Glenn Kastend2123e62015-01-29 10:02:44 -0800250 } else {
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800251 ALOGV("warmup cycle %d out of range: %.03f ms", mWarmupCycles, nsec * 1e-9);
252 mWarmupConsecutiveInRangeCycles = 0;
Glenn Kastend2123e62015-01-29 10:02:44 -0800253 }
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800254 if ((mWarmupConsecutiveInRangeCycles >= MIN_WARMUP_CYCLES) ||
255 (mWarmupCycles >= MAX_WARMUP_CYCLES)) {
256 mIsWarm = true;
257 mDumpState->mMeasuredWarmupTs = mMeasuredWarmupTs;
258 mDumpState->mWarmupCycles = mWarmupCycles;
Eric Tanfefe3162018-09-07 10:09:11 -0700259 const double measuredWarmupMs = (mMeasuredWarmupTs.tv_sec * 1e3) +
260 (mMeasuredWarmupTs.tv_nsec * 1e-6);
261 LOG_WARMUP_TIME(measuredWarmupMs);
Glenn Kasten22340022014-04-07 12:04:41 -0700262 }
263 }
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800264 mSleepNs = -1;
265 if (mIsWarm) {
266 if (sec > 0 || nsec > mUnderrunNs) {
Andy Hungf0859f32023-05-25 16:28:04 -0700267 ATRACE_NAME("underrun"); // NOLINT(misc-const-correctness)
Glenn Kasten22340022014-04-07 12:04:41 -0700268 // FIXME only log occasionally
269 ALOGV("underrun: time since last cycle %d.%03ld sec",
270 (int) sec, nsec / 1000000L);
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800271 mDumpState->mUnderruns++;
Eric Tanfefe3162018-09-07 10:09:11 -0700272 LOG_UNDERRUN(audio_utils_ns_from_timespec(&newTs));
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800273 mIgnoreNextOverrun = true;
274 } else if (nsec < mOverrunNs) {
275 if (mIgnoreNextOverrun) {
276 mIgnoreNextOverrun = false;
Glenn Kasten22340022014-04-07 12:04:41 -0700277 } else {
278 // FIXME only log occasionally
279 ALOGV("overrun: time since last cycle %d.%03ld sec",
280 (int) sec, nsec / 1000000L);
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800281 mDumpState->mOverruns++;
Eric Tanfefe3162018-09-07 10:09:11 -0700282 LOG_OVERRUN(audio_utils_ns_from_timespec(&newTs));
Glenn Kasten22340022014-04-07 12:04:41 -0700283 }
284 // This forces a minimum cycle time. It:
285 // - compensates for an audio HAL with jitter due to sample rate conversion
286 // - works with a variable buffer depth audio HAL that never pulls at a
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800287 // rate < than mOverrunNs per buffer.
Glenn Kasten22340022014-04-07 12:04:41 -0700288 // - recovers from overrun immediately after underrun
289 // It doesn't work with a non-blocking audio HAL.
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800290 mSleepNs = mForceNs - nsec;
Glenn Kasten22340022014-04-07 12:04:41 -0700291 } else {
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800292 mIgnoreNextOverrun = false;
Glenn Kasten22340022014-04-07 12:04:41 -0700293 }
294 }
Glenn Kasten214b4062015-03-02 14:15:47 -0800295#ifdef FAST_THREAD_STATISTICS
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800296 if (mIsWarm) {
Glenn Kasten22340022014-04-07 12:04:41 -0700297 // advance the FIFO queue bounds
Andy Hungf0859f32023-05-25 16:28:04 -0700298 const size_t i = mBounds & (mDumpState->mSamplingN - 1);
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800299 mBounds = (mBounds & 0xFFFF0000) | ((mBounds + 1) & 0xFFFF);
300 if (mFull) {
Ivan Lozano77657142018-01-02 21:01:16 +0000301 //mBounds += 0x10000;
302 __builtin_add_overflow(mBounds, 0x10000, &mBounds);
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800303 } else if (!(mBounds & (mDumpState->mSamplingN - 1))) {
304 mFull = true;
Glenn Kasten22340022014-04-07 12:04:41 -0700305 }
306 // compute the delta value of clock_gettime(CLOCK_MONOTONIC)
307 uint32_t monotonicNs = nsec;
308 if (sec > 0 && sec < 4) {
wendy lincd4c7242019-06-12 10:37:11 +0800309 monotonicNs += sec * 1000000000U; // unsigned to prevent signed overflow.
Glenn Kasten22340022014-04-07 12:04:41 -0700310 }
311 // compute raw CPU load = delta value of clock_gettime(CLOCK_THREAD_CPUTIME_ID)
312 uint32_t loadNs = 0;
313 struct timespec newLoad;
314 rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &newLoad);
315 if (rc == 0) {
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800316 if (mOldLoadValid) {
317 sec = newLoad.tv_sec - mOldLoad.tv_sec;
318 nsec = newLoad.tv_nsec - mOldLoad.tv_nsec;
Glenn Kasten22340022014-04-07 12:04:41 -0700319 if (nsec < 0) {
320 --sec;
321 nsec += 1000000000;
322 }
323 loadNs = nsec;
324 if (sec > 0 && sec < 4) {
wendy lincd4c7242019-06-12 10:37:11 +0800325 loadNs += sec * 1000000000U; // unsigned to prevent signed overflow.
Glenn Kasten22340022014-04-07 12:04:41 -0700326 }
327 } else {
328 // first time through the loop
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800329 mOldLoadValid = true;
Glenn Kasten22340022014-04-07 12:04:41 -0700330 }
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800331 mOldLoad = newLoad;
Glenn Kasten22340022014-04-07 12:04:41 -0700332 }
333#ifdef CPU_FREQUENCY_STATISTICS
334 // get the absolute value of CPU clock frequency in kHz
335 int cpuNum = sched_getcpu();
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800336 uint32_t kHz = mTcu.getCpukHz(cpuNum);
Glenn Kasten22340022014-04-07 12:04:41 -0700337 kHz = (kHz << 4) | (cpuNum & 0xF);
338#endif
339 // save values in FIFO queues for dumpsys
340 // these stores #1, #2, #3 are not atomic with respect to each other,
341 // or with respect to store #4 below
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800342 mDumpState->mMonotonicNs[i] = monotonicNs;
Eric Tancf3d82c2018-09-04 15:44:45 -0700343 LOG_WORK_TIME(monotonicNs);
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800344 mDumpState->mLoadNs[i] = loadNs;
Glenn Kasten22340022014-04-07 12:04:41 -0700345#ifdef CPU_FREQUENCY_STATISTICS
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800346 mDumpState->mCpukHz[i] = kHz;
Glenn Kasten22340022014-04-07 12:04:41 -0700347#endif
348 // this store #4 is not atomic with respect to stores #1, #2, #3 above, but
349 // the newest open & oldest closed halves are atomic with respect to each other
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800350 mDumpState->mBounds = mBounds;
Glenn Kastenf9715e42016-07-13 14:02:03 -0700351 ATRACE_INT(mCycleMs, monotonicNs / 1000000);
352 ATRACE_INT(mLoadUs, loadNs / 1000);
Glenn Kasten22340022014-04-07 12:04:41 -0700353 }
354#endif
355 } else {
356 // first time through the loop
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800357 mOldTsValid = true;
358 mSleepNs = mPeriodNs;
359 mIgnoreNextOverrun = true;
Glenn Kasten22340022014-04-07 12:04:41 -0700360 }
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800361 mOldTs = newTs;
Glenn Kasten22340022014-04-07 12:04:41 -0700362 } else {
363 // monotonic clock is broken
Glenn Kastene4a7ce22015-03-03 11:23:17 -0800364 mOldTsValid = false;
365 mSleepNs = mPeriodNs;
Glenn Kasten22340022014-04-07 12:04:41 -0700366 }
367
368 } // for (;;)
369
370 // never return 'true'; Thread::_threadLoop() locks mutex which can result in priority inversion
371}
372
373} // namespace android